2021-09-28 18:04:05 +00:00
|
|
|
#include <vector>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <cstdint>
|
|
|
|
|
|
|
|
#include <GLES/gl.h>
|
|
|
|
|
2021-01-27 21:26:19 +00:00
|
|
|
#include <libreborn/libreborn.h>
|
2021-09-12 03:18:12 +00:00
|
|
|
#include <symbols/minecraft.h>
|
2020-12-02 23:18:49 +00:00
|
|
|
|
2022-06-25 21:30:08 +00:00
|
|
|
#include <mods/misc/misc.h>
|
|
|
|
#include <mods/feature/feature.h>
|
2023-10-19 05:23:34 +00:00
|
|
|
#include <mods/textures/textures.h>
|
2022-06-25 21:30:08 +00:00
|
|
|
#include <mods/init/init.h>
|
2020-12-02 23:18:49 +00:00
|
|
|
|
2023-11-11 05:44:26 +00:00
|
|
|
#include "stb_image.h"
|
|
|
|
|
2021-06-30 23:41:18 +00:00
|
|
|
// Animated Water
|
2024-01-06 11:30:23 +00:00
|
|
|
static void Minecraft_tick_injection(Minecraft *minecraft) {
|
2020-12-02 23:18:49 +00:00
|
|
|
// Tick Dynamic Textures
|
2024-01-06 11:30:23 +00:00
|
|
|
Textures *textures = minecraft->textures;
|
2020-12-02 23:18:49 +00:00
|
|
|
if (textures != NULL) {
|
|
|
|
(*Textures_tick)(textures, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-28 18:04:05 +00:00
|
|
|
// Store Texture Sizes
|
|
|
|
struct texture_data {
|
|
|
|
GLint id;
|
|
|
|
GLsizei width;
|
|
|
|
GLsizei height;
|
|
|
|
};
|
|
|
|
static std::vector<texture_data> &get_texture_data() {
|
|
|
|
static std::vector<texture_data> data;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
HOOK(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;
|
|
|
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &data.id);
|
|
|
|
data.width = width;
|
|
|
|
data.height = height;
|
|
|
|
get_texture_data().push_back(data);
|
|
|
|
|
|
|
|
// Call Original Method
|
|
|
|
ensure_glTexImage2D();
|
|
|
|
(*real_glTexImage2D)(target, level, internalformat, width, height, border, format, type, pixels);
|
|
|
|
}
|
|
|
|
HOOK(glDeleteTextures, void, (GLsizei n, const GLuint *textures)) {
|
|
|
|
// Remove Old Data
|
|
|
|
for (int i = 0; i < n; i++) {
|
2021-09-30 23:37:24 +00:00
|
|
|
GLint id = textures[i];
|
2021-09-28 18:04:05 +00:00
|
|
|
std::vector<texture_data>::iterator it = get_texture_data().begin();
|
|
|
|
while (it != get_texture_data().end()) {
|
|
|
|
texture_data data = *it;
|
|
|
|
if (data.id == id) {
|
|
|
|
it = get_texture_data().erase(it);
|
|
|
|
} else {
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call Original Method
|
|
|
|
ensure_glDeleteTextures();
|
|
|
|
(*real_glDeleteTextures)(n, textures);
|
|
|
|
}
|
|
|
|
static void get_texture_size(GLint id, GLsizei *width, GLsizei *height) {
|
|
|
|
// Iterate
|
|
|
|
std::vector<texture_data>::iterator it = get_texture_data().begin();
|
|
|
|
while (it != get_texture_data().end()) {
|
|
|
|
texture_data data = *it;
|
|
|
|
if (data.id == id) {
|
|
|
|
// Found
|
|
|
|
*width = data.width;
|
|
|
|
*height = data.height;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
// Not Found
|
2022-05-29 22:44:27 +00:00
|
|
|
*width = 0;
|
|
|
|
*height = 0;
|
2021-09-28 18:04:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Scale Texture (Remember To Free)
|
|
|
|
#define PIXEL_SIZE 4
|
|
|
|
static int get_line_size(int width) {
|
|
|
|
int line_size = width * PIXEL_SIZE;
|
|
|
|
{
|
|
|
|
// Handle Alignment
|
|
|
|
int alignment;
|
|
|
|
glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
|
|
|
|
// Round
|
|
|
|
int diff = line_size % alignment;
|
|
|
|
if (diff > 0) {
|
|
|
|
line_size = line_size + (alignment - diff);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return line_size;
|
|
|
|
}
|
|
|
|
static void *scale_texture(const unsigned char *src, GLsizei old_width, GLsizei old_height, GLsizei new_width, GLsizei new_height) {
|
|
|
|
int old_line_size = get_line_size(old_width);
|
|
|
|
int new_line_size = get_line_size(new_width);
|
|
|
|
|
|
|
|
// Allocate
|
|
|
|
unsigned char *dst = (unsigned char *) malloc(new_height * new_line_size);
|
|
|
|
ALLOC_CHECK(dst);
|
|
|
|
|
|
|
|
// Scale
|
|
|
|
for (int new_x = 0; new_x < new_width; new_x++) {
|
|
|
|
int old_x = (int) (((float) new_x / (float) new_width) * (float) old_width);
|
|
|
|
for (int new_y = 0; new_y < new_height; new_y++) {
|
|
|
|
int old_y = (int) (((float) new_y / (float) new_height) * (float) old_height);
|
|
|
|
|
|
|
|
// Find Position
|
|
|
|
int new_position = (new_y * new_line_size) + (new_x * PIXEL_SIZE);
|
|
|
|
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
|
2023-10-19 05:23:34 +00:00
|
|
|
void 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) {
|
2021-09-28 18:04:05 +00:00
|
|
|
// Get Current Texture Size
|
|
|
|
GLint current_texture;
|
|
|
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
|
|
|
GLsizei texture_width;
|
|
|
|
GLsizei texture_height;
|
|
|
|
get_texture_size(current_texture, &texture_width, &texture_height);
|
|
|
|
|
|
|
|
// Calculate Factor
|
2023-10-19 05:23:34 +00:00
|
|
|
float width_factor = ((float) texture_width) / ((float) normal_texture_width);
|
|
|
|
float height_factor = ((float) texture_height) / ((float) normal_texture_height);
|
2021-09-28 18:04:05 +00:00
|
|
|
|
|
|
|
// Only Scale If Needed
|
|
|
|
if (width_factor == 1.0f && height_factor == 1.0f) {
|
|
|
|
// No Scaling
|
|
|
|
glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
|
|
|
|
} else {
|
|
|
|
// Check
|
|
|
|
if (format != GL_RGBA || type != GL_UNSIGNED_BYTE) {
|
|
|
|
// Pixels Must Be 4 Bytes
|
2022-04-15 01:12:42 +00:00
|
|
|
ERR("Unsupported Texture Format For Scaling");
|
2021-09-28 18:04:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Scale
|
|
|
|
GLsizei new_width = width * width_factor;
|
|
|
|
GLsizei new_height = height * height_factor;
|
|
|
|
void *new_pixels = scale_texture((const unsigned char *) pixels, width, height, new_width, new_height);
|
|
|
|
|
|
|
|
// Call Original Method
|
|
|
|
GLint new_xoffset = xoffset * width_factor;
|
|
|
|
GLint new_yoffset = yoffset * height_factor;
|
|
|
|
glTexSubImage2D(target, level, new_xoffset, new_yoffset, new_width, new_height, format, type, new_pixels);
|
|
|
|
|
|
|
|
// Free
|
|
|
|
free(new_pixels);
|
|
|
|
}
|
|
|
|
}
|
2023-10-19 05:23:34 +00:00
|
|
|
static void Textures_tick_glTexSubImage2D_injection(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {
|
|
|
|
glTexSubImage2D_with_scaling(target, level, xoffset, yoffset, width, height, 256, 256, format, type, pixels);
|
|
|
|
}
|
2021-09-28 18:04:05 +00:00
|
|
|
|
2023-11-11 05:44:26 +00:00
|
|
|
// Load Textures
|
2024-01-06 11:30:23 +00:00
|
|
|
static Texture AppPlatform_linux_loadTexture_injection(__attribute__((unused)) AppPlatform_linux *app_platform, std::string *path, bool b) {
|
2023-11-11 05:44:26 +00:00
|
|
|
Texture out;
|
2024-01-06 11:30:23 +00:00
|
|
|
std::string real_path = *path;
|
2023-11-11 05:44:26 +00:00
|
|
|
if (b) {
|
|
|
|
real_path = "data/images/" + real_path;
|
|
|
|
}
|
|
|
|
|
2024-01-06 11:30:23 +00:00
|
|
|
// Empty Texture
|
|
|
|
out.width = 0;
|
|
|
|
out.height = 0;
|
|
|
|
out.data = NULL;
|
|
|
|
out.field3_0xc = 0;
|
|
|
|
out.field4_0x10 = true;
|
|
|
|
out.field5_0x11 = false;
|
|
|
|
out.field6_0x14 = 0;
|
|
|
|
out.field7_0x18 = -1;
|
|
|
|
|
2023-11-11 05:44:26 +00:00
|
|
|
// Read Image
|
|
|
|
int width = 0, height = 0, channels = 0;
|
|
|
|
stbi_uc *img = stbi_load(real_path.c_str(), &width, &height, &channels, STBI_rgb_alpha);
|
|
|
|
if (!img)
|
|
|
|
{
|
|
|
|
// Failed To Parse Image
|
|
|
|
WARN("Unable To Load Texture: %s", real_path.c_str());
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy Image
|
|
|
|
unsigned char *img2 = new unsigned char[width * height * channels];
|
|
|
|
memcpy(img2, img, width * height * channels);
|
|
|
|
stbi_image_free(img);
|
|
|
|
|
|
|
|
// Create Texture
|
|
|
|
out.width = width;
|
|
|
|
out.height = height;
|
|
|
|
out.data = img2;
|
|
|
|
|
|
|
|
// Return
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2021-06-30 23:41:18 +00:00
|
|
|
// Init
|
2020-12-02 23:18:49 +00:00
|
|
|
void init_textures() {
|
2021-06-30 23:41:18 +00:00
|
|
|
// Tick Dynamic Textures (Animated Water)
|
2022-04-10 00:01:16 +00:00
|
|
|
if (feature_has("Animated Water", server_disabled)) {
|
2022-05-29 22:44:27 +00:00
|
|
|
misc_run_on_tick(Minecraft_tick_injection);
|
2020-12-02 23:18:49 +00:00
|
|
|
}
|
2021-09-28 18:04:05 +00:00
|
|
|
|
|
|
|
// Scale Animated Textures
|
|
|
|
overwrite_call((void *) 0x53274, (void *) Textures_tick_glTexSubImage2D_injection);
|
2023-11-11 05:44:26 +00:00
|
|
|
|
|
|
|
// Load Textures
|
2024-01-06 11:30:23 +00:00
|
|
|
overwrite((void *) AppPlatform_linux_loadTexture_non_virtual, (void *) AppPlatform_linux_loadTexture_injection);
|
2021-06-30 22:38:43 +00:00
|
|
|
}
|