2021-06-30 19:41:18 -04:00
|
|
|
#include <GLES/gl.h>
|
|
|
|
|
|
|
|
#include <libreborn/libreborn.h>
|
2021-09-11 23:18:12 -04:00
|
|
|
#include <symbols/minecraft.h>
|
2024-10-26 02:00:16 -04:00
|
|
|
#include <media-layer/core.h>
|
2021-06-30 19:41:18 -04:00
|
|
|
|
2022-06-25 17:30:08 -04:00
|
|
|
#include <mods/feature/feature.h>
|
2024-10-26 02:00:16 -04:00
|
|
|
#include <mods/misc/misc.h>
|
|
|
|
#include <mods/textures/textures.h>
|
|
|
|
#include <mods/atlas/atlas.h>
|
2022-06-25 17:30:08 -04:00
|
|
|
#include <mods/init/init.h>
|
2021-06-30 19:41:18 -04:00
|
|
|
|
2024-10-26 02:00:16 -04:00
|
|
|
// 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++;
|
|
|
|
}
|
2021-06-30 19:41:18 -04:00
|
|
|
}
|
|
|
|
}
|
2024-10-26 02:00:16 -04:00
|
|
|
}
|
|
|
|
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);
|
2021-06-30 19:41:18 -04:00
|
|
|
|
2024-10-26 02:00:16 -04:00
|
|
|
// 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);
|
2024-10-20 01:19:08 -04:00
|
|
|
media_glDisable(GL_DEPTH_TEST);
|
2021-06-30 19:41:18 -04:00
|
|
|
|
2024-10-26 02:00:16 -04:00
|
|
|
// Re-Upload Textures
|
|
|
|
Textures *textures = Textures::allocate();
|
|
|
|
textures->constructor(&minecraft->options, minecraft->platform());
|
2021-06-30 19:41:18 -04:00
|
|
|
|
2024-10-26 02:00:16 -04:00
|
|
|
// Render
|
|
|
|
render_atlas(textures);
|
2021-06-30 19:41:18 -04:00
|
|
|
|
2024-10-26 02:00:16 -04:00
|
|
|
// 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;
|
|
|
|
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);
|
2022-01-01 19:04:58 -05:00
|
|
|
}
|
2021-06-30 19:41:18 -04:00
|
|
|
}
|
|
|
|
|
2024-10-26 02:00:16 -04:00
|
|
|
// Restore Old Context
|
|
|
|
textures->destructor();
|
|
|
|
::operator delete(textures);
|
|
|
|
media_end_offscreen_render();
|
2021-06-30 19:41:18 -04:00
|
|
|
|
2024-10-26 02:00:16 -04:00
|
|
|
// Upload Texture
|
|
|
|
minecraft->textures->assignTexture("gui/gui_blocks.png", texture);
|
|
|
|
DEBUG("Generated gui_blocks Atlas");
|
2021-06-30 19:41:18 -04:00
|
|
|
}
|
|
|
|
|
2024-10-26 02:00:16 -04:00
|
|
|
// 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
|
|
|
|
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();
|
2022-01-01 19:04:58 -05:00
|
|
|
}
|
2021-06-30 19:41:18 -04:00
|
|
|
|
2024-10-26 02:00:16 -04:00
|
|
|
// 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);
|
2022-01-01 19:04:58 -05:00
|
|
|
}
|
2021-06-30 19:41:18 -04:00
|
|
|
|
2024-10-26 02:00:16 -04:00
|
|
|
// 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();
|
2021-06-30 19:41:18 -04:00
|
|
|
}
|
|
|
|
|
2024-10-26 02:00:16 -04:00
|
|
|
// 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);
|
|
|
|
}
|
2024-07-17 06:42:58 -04:00
|
|
|
}
|
|
|
|
|
2021-06-30 19:41:18 -04:00
|
|
|
// Init
|
|
|
|
void init_atlas() {
|
2024-10-26 02:00:16 -04:00
|
|
|
// 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);
|
2021-06-30 19:41:18 -04:00
|
|
|
}
|
|
|
|
}
|