Files
coah80-LegacyVulkEdition/Minecraft.Client/CrossPlatform/NkContainerMenus.cpp

758 lines
29 KiB
C++

#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_STANDARD_VARARGS
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#include "nuklear.h"
#include "NkContainerMenus.h"
#include "NkCommon.h"
#include "MenuScreens.h"
#include "NuklearBridge.h"
#include <cstring>
namespace lve { namespace ui {
static const float BASE_W = 1280.0f;
static const float BASE_H = 720.0f;
static const float SLOT_SIZE = 36.0f;
static const float SLOT_PAD = 4.0f;
static const float PANEL_PAD = 12.0f;
static const float SECTION_GAP = 8.0f;
static const float LABEL_H = 20.0f;
static const float INV_COLS = 9.0f;
static const float INV_ROWS = 3.0f;
static const float SHADOW_OFF = 2.0f;
static MenuTextureSlot loadSlot(const char *path)
{
int w = 0, h = 0;
struct nk_image img = loadTextureWithSize(path, &w, &h);
return {img.handle.id, w, h};
}
bool loadContainerMenuTextures(ContainerMenuTextures &out)
{
out.flameOn = loadSlot("../Assets/ui/skinHDGraphicsInGame/94_Flame_On.png");
out.flameOff = loadSlot("../Assets/ui/skinHDGraphicsInGame/95_Flame_Off.png");
out.arrowOn = loadSlot("../Assets/ui/skinHDGraphicsInGame/96_Arrow_On.png");
out.arrowOff = loadSlot("../Assets/ui/skinHDGraphicsInGame/97_Arrow_Off.png");
out.brewingStand = loadSlot("../Assets/ui/skinHDGraphicsInGame/106_BrewingStand.png");
out.brewingBubblesOn = loadSlot("../Assets/ui/skinHDGraphicsInGame/107_BrewingBubbles_On.png");
out.brewingBubblesOff = loadSlot("../Assets/ui/skinHDGraphicsInGame/108_BrewingBubbles_Off.png");
out.brewingArrowOn = loadSlot("../Assets/ui/skinHDGraphicsInGame/109_BrewingArrow_On.png");
out.brewingArrowOff = loadSlot("../Assets/ui/skinHDGraphicsInGame/110_BrewingArrow_Off.png");
out.enchantBtnActive = loadSlot("../Assets/ui/skinHDGraphicsInGame/104_EnchantmentButtonActive.png");
out.enchantBtnSelected = loadSlot("../Assets/ui/skinHDGraphicsInGame/102_EnchantmentButtonSelected.png");
out.enchantBtnEmpty = loadSlot("../Assets/ui/skinHDGraphicsInGame/103_EnchantmentButtonEmpty.png");
out.enchantSlot = loadSlot("../Assets/ui/skinHDGraphicsInGame/105_Enchant_Slot.png");
out.anvilPlus = loadSlot("../Assets/ui/skinHDGraphicsInGame/57_AnvilPlus.png");
out.anvilHammer = loadSlot("../Assets/ui/skinHDGraphicsInGame/62_AnvilHammer.png");
out.anvilCross = loadSlot("../Assets/ui/skinHDGraphicsInGame/67_AnvilCross.png");
out.slotHighlight = loadSlot("../Assets/ui/skinHDGraphicsInGame/130_SlotHighlight.png");
out.iconHolder = loadSlot("../Assets/ui/skinHDGraphicsInGame/129_IconHolder_1x1border.png");
out.textInputBg = loadSlot("../Assets/ui/skinHDGraphicsInGame/75_TextInputBG.png");
out.textInputBorder = loadSlot("../Assets/ui/skinHDGraphicsInGame/73_TextInputBGBorder.png");
out.loaded = (out.flameOn.w > 0 && out.arrowOn.w > 0 && out.iconHolder.w > 0);
return out.loaded;
}
static void drawSlotGrid(struct nk_command_buffer *canvas, float x, float y,
int cols, int rows, float slotSz, float pad,
ContainerMenuTextures &cTex)
{
struct nk_image holderImg = slotToNkImage(cTex.iconHolder);
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
float sx = x + (float)c * (slotSz + pad);
float sy = y + (float)r * (slotSz + pad);
if (cTex.iconHolder.w > 0)
nk_draw_image(canvas, nk_rect(sx, sy, slotSz, slotSz), &holderImg, nk_rgb(255, 255, 255));
else
nk_fill_rect(canvas, nk_rect(sx, sy, slotSz, slotSz), 0, nk_rgb(80, 80, 80));
}
}
}
static void drawShadowTextCentered(struct nk_command_buffer *canvas,
const struct nk_user_font *font,
const char *text, float x, float y, float w)
{
if (font == nullptr) return;
int len = (int)strlen(text);
float tw = font->width(font->userdata, font->height, text, len);
float tx = x + (w - tw) * 0.5f;
nk_draw_text(canvas, nk_rect(tx + SHADOW_OFF, y + SHADOW_OFF, tw, font->height),
text, len, font, nk_rgba(0, 0, 0, 0), nk_rgb(0x3F, 0x3F, 0x3F));
nk_draw_text(canvas, nk_rect(tx, y, tw, font->height),
text, len, font, nk_rgba(0, 0, 0, 0), nk_rgb(255, 255, 255));
}
static void drawShadowTextLeft(struct nk_command_buffer *canvas,
const struct nk_user_font *font,
const char *text, float x, float y)
{
if (font == nullptr) return;
int len = (int)strlen(text);
float tw = font->width(font->userdata, font->height, text, len);
nk_draw_text(canvas, nk_rect(x + SHADOW_OFF, y + SHADOW_OFF, tw, font->height),
text, len, font, nk_rgba(0, 0, 0, 0), nk_rgb(0x3F, 0x3F, 0x3F));
nk_draw_text(canvas, nk_rect(x, y, tw, font->height),
text, len, font, nk_rgba(0, 0, 0, 0), nk_rgb(255, 255, 255));
}
static void drawShadowTextRight(struct nk_command_buffer *canvas,
const struct nk_user_font *font,
const char *text, float x, float y, float w)
{
if (font == nullptr) return;
int len = (int)strlen(text);
float tw = font->width(font->userdata, font->height, text, len);
float tx = x + w - tw;
nk_draw_text(canvas, nk_rect(tx + SHADOW_OFF, y + SHADOW_OFF, tw, font->height),
text, len, font, nk_rgba(0, 0, 0, 0), nk_rgb(0x3F, 0x3F, 0x3F));
nk_draw_text(canvas, nk_rect(tx, y, tw, font->height),
text, len, font, nk_rgba(0, 0, 0, 0), nk_rgb(255, 255, 255));
}
static void drawShadowTextCenteredColor(struct nk_command_buffer *canvas,
const struct nk_user_font *font,
const char *text, float x, float y,
float w, struct nk_color color)
{
if (font == nullptr) return;
int len = (int)strlen(text);
float tw = font->width(font->userdata, font->height, text, len);
float tx = x + (w - tw) * 0.5f;
nk_draw_text(canvas, nk_rect(tx + SHADOW_OFF, y + SHADOW_OFF, tw, font->height),
text, len, font, nk_rgba(0, 0, 0, 0), nk_rgb(0x3F, 0x3F, 0x3F));
nk_draw_text(canvas, nk_rect(tx, y, tw, font->height),
text, len, font, nk_rgba(0, 0, 0, 0), color);
}
static void drawProgressBar(struct nk_command_buffer *canvas,
const MenuTextureSlot &onSlot, const MenuTextureSlot &offSlot,
float x, float y, float w, float h,
float progress, bool vertical)
{
if (offSlot.w > 0 && offSlot.h > 0) {
struct nk_image offImg = nk_image_id(offSlot.id);
nk_draw_image(canvas, nk_rect(x, y, w, h), &offImg, nk_rgb(255, 255, 255));
}
if (progress > 0.0f && onSlot.w > 0 && onSlot.h > 0) {
float p = progress > 1.0f ? 1.0f : progress;
struct nk_image onImg = nk_image_id(onSlot.id);
if (vertical) {
float filledH = h * p;
nk_draw_image(canvas, nk_rect(x, y + h - filledH, w, filledH), &onImg, nk_rgb(255, 255, 255));
} else {
float filledW = w * p;
nk_draw_image(canvas, nk_rect(x, y, filledW, h), &onImg, nk_rgb(255, 255, 255));
}
}
}
static float gridW(float cols, float slotSz, float pad)
{
return cols * slotSz + (cols - 1.0f) * pad;
}
static float gridH(float rows, float slotSz, float pad)
{
return rows * slotSz + (rows - 1.0f) * pad;
}
void renderFurnace(nk_context *ctx, int winW, int winH, MenuTextures &tex, ContainerMenuTextures &cTex)
{
float scaleX = (float)winW / BASE_W;
float scaleY = (float)winH / BASE_H;
float scale = scaleX < scaleY ? scaleX : scaleY;
float slotSz = SLOT_SIZE * scale;
float pad = SLOT_PAD * scale;
float panelPad = PANEL_PAD * scale;
float gap = SECTION_GAP * scale;
float labelH = LABEL_H * scale;
float igw = gridW(INV_COLS, slotSz, pad);
float igh3 = gridH(INV_ROWS, slotSz, pad);
float flameW = 28.0f * scale;
float flameH = 28.0f * scale;
float arrowW = 44.0f * scale;
float arrowH = 32.0f * scale;
float leftColH = slotSz + pad + flameH + pad + slotSz;
float furnaceRowW = slotSz + gap * 2.0f + arrowW + gap + slotSz;
float topW = igw > furnaceRowW ? igw : furnaceRowW;
float totalH = labelH + gap + leftColH + gap * 2.0f + labelH + gap + igh3 + gap + slotSz;
float panelW = topW + panelPad * 2.0f;
float panelH = totalH + panelPad * 2.0f;
float panelX = ((float)winW - panelW) * 0.5f;
float panelY = ((float)winH - panelH) * 0.5f;
pushCleanStyle(ctx);
if (nk_begin(ctx, "FurnaceMenu", nk_rect(0, 0, (float)winW, (float)winH),
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) {
drawDirtBg(ctx, winW, winH, tex);
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
const struct nk_user_font *font = ctx->style.font;
nk_fill_rect(canvas, nk_rect(panelX, panelY, panelW, panelH), 4.0f * scale, nk_rgba(0, 0, 0, 180));
float cx = panelX + panelPad;
float cy = panelY + panelPad;
drawShadowTextCentered(canvas, font, "Furnace", cx, cy, topW);
cy += labelH + gap;
float fsx = cx + (topW - furnaceRowW) * 0.5f;
float fsy = cy;
drawShadowTextLeft(canvas, font, "Ingredient", fsx, fsy - labelH);
drawSlotGrid(canvas, fsx, fsy, 1, 1, slotSz, pad, cTex);
float flameX = fsx + (slotSz - flameW) * 0.5f;
float flameY = fsy + slotSz + pad;
drawProgressBar(canvas, cTex.flameOn, cTex.flameOff,
flameX, flameY, flameW, flameH, 0.0f, true);
drawShadowTextLeft(canvas, font, "Fuel", fsx, flameY + flameH + pad - labelH + slotSz + gap * 0.5f);
float fuelY = flameY + flameH + pad;
drawSlotGrid(canvas, fsx, fuelY, 1, 1, slotSz, pad, cTex);
float arrowX = fsx + slotSz + gap * 2.0f;
float arrowY = fsy + (leftColH - arrowH) * 0.5f;
drawProgressBar(canvas, cTex.arrowOn, cTex.arrowOff,
arrowX, arrowY, arrowW, arrowH, 0.0f, false);
float resultX = arrowX + arrowW + gap;
float resultY = arrowY + (arrowH - slotSz) * 0.5f;
drawSlotGrid(canvas, resultX, resultY, 1, 1, slotSz, pad, cTex);
cy = fsy + leftColH + gap * 2.0f;
float invX = cx + (topW - igw) * 0.5f;
drawShadowTextLeft(canvas, font, "Inventory", invX, cy);
cy += labelH + gap;
drawSlotGrid(canvas, invX, cy, 9, 3, slotSz, pad, cTex);
cy += igh3 + gap;
drawSlotGrid(canvas, invX, cy, 9, 1, slotSz, pad, cTex);
drawControllerPrompts(ctx, winW, winH, tex);
}
nk_end(ctx);
popCleanStyle(ctx);
}
void renderContainer(nk_context *ctx, int winW, int winH, MenuTextures &tex, ContainerMenuTextures &cTex, bool isLargeChest)
{
float scaleX = (float)winW / BASE_W;
float scaleY = (float)winH / BASE_H;
float scale = scaleX < scaleY ? scaleX : scaleY;
float slotSz = SLOT_SIZE * scale;
float pad = SLOT_PAD * scale;
float panelPad = PANEL_PAD * scale;
float gap = SECTION_GAP * scale;
float labelH = LABEL_H * scale;
float igw = gridW(INV_COLS, slotSz, pad);
float igh3 = gridH(INV_ROWS, slotSz, pad);
int chestRows = isLargeChest ? 6 : 3;
float chestH = gridH((float)chestRows, slotSz, pad);
const char *title = isLargeChest ? "Large Chest" : "Chest";
float totalH = labelH + gap + chestH + gap * 2.0f + labelH + gap + igh3 + gap + slotSz;
float panelW = igw + panelPad * 2.0f;
float panelH = totalH + panelPad * 2.0f;
float panelX = ((float)winW - panelW) * 0.5f;
float panelY = ((float)winH - panelH) * 0.5f;
pushCleanStyle(ctx);
if (nk_begin(ctx, "ContainerMenu", nk_rect(0, 0, (float)winW, (float)winH),
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) {
drawDirtBg(ctx, winW, winH, tex);
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
const struct nk_user_font *font = ctx->style.font;
nk_fill_rect(canvas, nk_rect(panelX, panelY, panelW, panelH), 4.0f * scale, nk_rgba(0, 0, 0, 180));
float cx = panelX + panelPad;
float cy = panelY + panelPad;
drawShadowTextCentered(canvas, font, title, cx, cy, igw);
cy += labelH + gap;
drawSlotGrid(canvas, cx, cy, 9, chestRows, slotSz, pad, cTex);
cy += chestH + gap * 2.0f;
drawShadowTextLeft(canvas, font, "Inventory", cx, cy);
cy += labelH + gap;
drawSlotGrid(canvas, cx, cy, 9, 3, slotSz, pad, cTex);
cy += igh3 + gap;
drawSlotGrid(canvas, cx, cy, 9, 1, slotSz, pad, cTex);
drawControllerPrompts(ctx, winW, winH, tex);
}
nk_end(ctx);
popCleanStyle(ctx);
}
void renderAnvil(nk_context *ctx, int winW, int winH, MenuTextures &tex, ContainerMenuTextures &cTex)
{
float scaleX = (float)winW / BASE_W;
float scaleY = (float)winH / BASE_H;
float scale = scaleX < scaleY ? scaleX : scaleY;
float slotSz = SLOT_SIZE * scale;
float pad = SLOT_PAD * scale;
float panelPad = PANEL_PAD * scale;
float gap = SECTION_GAP * scale;
float labelH = LABEL_H * scale;
float igw = gridW(INV_COLS, slotSz, pad);
float igh3 = gridH(INV_ROWS, slotSz, pad);
float plusW = 20.0f * scale;
float plusH = 20.0f * scale;
float hammerW = 28.0f * scale;
float hammerH = 28.0f * scale;
float crossW = 28.0f * scale;
float crossH = 28.0f * scale;
float slotsRowW = slotSz + gap + plusW + gap + slotSz + gap + hammerW + gap + slotSz;
float topW = igw > slotsRowW ? igw : slotsRowW;
float textInputW = topW;
float textInputH = 28.0f * scale;
float costLabelH = labelH;
float totalH = labelH + gap + textInputH + gap + slotSz + gap + costLabelH
+ gap * 2.0f + labelH + gap + igh3 + gap + slotSz;
float panelW = topW + panelPad * 2.0f;
float panelH = totalH + panelPad * 2.0f;
float panelX = ((float)winW - panelW) * 0.5f;
float panelY = ((float)winH - panelH) * 0.5f;
pushCleanStyle(ctx);
if (nk_begin(ctx, "AnvilMenu", nk_rect(0, 0, (float)winW, (float)winH),
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) {
drawDirtBg(ctx, winW, winH, tex);
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
const struct nk_user_font *font = ctx->style.font;
nk_fill_rect(canvas, nk_rect(panelX, panelY, panelW, panelH), 4.0f * scale, nk_rgba(0, 0, 0, 180));
float cx = panelX + panelPad;
float cy = panelY + panelPad;
drawShadowTextCentered(canvas, font, "Repair & Name", cx, cy, topW);
cy += labelH + gap;
if (cTex.textInputBorder.w > 0) {
struct nk_image borderImg = slotToNkImage(cTex.textInputBorder);
nk_draw_image(canvas, nk_rect(cx, cy, textInputW, textInputH), &borderImg, nk_rgb(255, 255, 255));
}
if (cTex.textInputBg.w > 0) {
struct nk_image bgImg = slotToNkImage(cTex.textInputBg);
nk_draw_image(canvas, nk_rect(cx + 2.0f * scale, cy + 2.0f * scale,
textInputW - 4.0f * scale, textInputH - 4.0f * scale),
&bgImg, nk_rgb(255, 255, 255));
}
cy += textInputH + gap;
float ssx = cx + (topW - slotsRowW) * 0.5f;
drawSlotGrid(canvas, ssx, cy, 1, 1, slotSz, pad, cTex);
float plusX = ssx + slotSz + gap;
float plusY = cy + (slotSz - plusH) * 0.5f;
if (cTex.anvilPlus.w > 0) {
struct nk_image img = slotToNkImage(cTex.anvilPlus);
nk_draw_image(canvas, nk_rect(plusX, plusY, plusW, plusH), &img, nk_rgb(255, 255, 255));
}
float s2x = plusX + plusW + gap;
drawSlotGrid(canvas, s2x, cy, 1, 1, slotSz, pad, cTex);
float hamX = s2x + slotSz + gap;
float hamY = cy + (slotSz - hammerH) * 0.5f;
if (cTex.anvilHammer.w > 0) {
struct nk_image img = slotToNkImage(cTex.anvilHammer);
nk_draw_image(canvas, nk_rect(hamX, hamY, hammerW, hammerH), &img, nk_rgb(255, 255, 255));
}
float resX = hamX + hammerW + gap;
drawSlotGrid(canvas, resX, cy, 1, 1, slotSz, pad, cTex);
if (cTex.anvilCross.w > 0) {
float crossX = resX + (slotSz - crossW) * 0.5f;
float crossY = cy + (slotSz - crossH) * 0.5f;
struct nk_image crossImg = slotToNkImage(cTex.anvilCross);
nk_draw_image(canvas, nk_rect(crossX, crossY, crossW, crossH), &crossImg, nk_rgb(255, 255, 255));
}
cy += slotSz + gap;
drawShadowTextCenteredColor(canvas, font, "Enchantment Cost: 0",
cx, cy, topW, nk_rgb(128, 252, 128));
cy += costLabelH + gap * 2.0f;
float invX = cx + (topW - igw) * 0.5f;
drawShadowTextLeft(canvas, font, "Inventory", invX, cy);
cy += labelH + gap;
drawSlotGrid(canvas, invX, cy, 9, 3, slotSz, pad, cTex);
cy += igh3 + gap;
drawSlotGrid(canvas, invX, cy, 9, 1, slotSz, pad, cTex);
drawControllerPrompts(ctx, winW, winH, tex);
}
nk_end(ctx);
popCleanStyle(ctx);
}
void renderBrewingStand(nk_context *ctx, int winW, int winH, MenuTextures &tex, ContainerMenuTextures &cTex)
{
float scaleX = (float)winW / BASE_W;
float scaleY = (float)winH / BASE_H;
float scale = scaleX < scaleY ? scaleX : scaleY;
float slotSz = SLOT_SIZE * scale;
float pad = SLOT_PAD * scale;
float panelPad = PANEL_PAD * scale;
float gap = SECTION_GAP * scale;
float labelH = LABEL_H * scale;
float igw = gridW(INV_COLS, slotSz, pad);
float igh3 = gridH(INV_ROWS, slotSz, pad);
float standW = 120.0f * scale;
float standH = 100.0f * scale;
float bubblesW = 16.0f * scale;
float bubblesH = 52.0f * scale;
float brewArrowW = 20.0f * scale;
float brewArrowH = 32.0f * scale;
float brewAreaH = standH + gap + slotSz;
float totalH = labelH + gap + slotSz + gap + brewAreaH + gap * 2.0f + labelH + gap + igh3 + gap + slotSz;
float panelW = igw + panelPad * 2.0f;
float panelH = totalH + panelPad * 2.0f;
float panelX = ((float)winW - panelW) * 0.5f;
float panelY = ((float)winH - panelH) * 0.5f;
pushCleanStyle(ctx);
if (nk_begin(ctx, "BrewingStandMenu", nk_rect(0, 0, (float)winW, (float)winH),
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) {
drawDirtBg(ctx, winW, winH, tex);
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
const struct nk_user_font *font = ctx->style.font;
nk_fill_rect(canvas, nk_rect(panelX, panelY, panelW, panelH), 4.0f * scale, nk_rgba(0, 0, 0, 180));
float cx = panelX + panelPad;
float cy = panelY + panelPad;
drawShadowTextCentered(canvas, font, "Brewing Stand", cx, cy, igw);
cy += labelH + gap;
float ingredientX = cx + (igw - slotSz) * 0.5f;
drawSlotGrid(canvas, ingredientX, cy, 1, 1, slotSz, pad, cTex);
cy += slotSz + gap;
float centerX = cx + igw * 0.5f;
float bubblesX = centerX - bubblesW * 0.5f - standW * 0.15f;
float bubblesY = cy;
drawProgressBar(canvas, cTex.brewingBubblesOn, cTex.brewingBubblesOff,
bubblesX, bubblesY, bubblesW, bubblesH, 0.0f, true);
float baX = centerX + standW * 0.15f - brewArrowW * 0.5f;
float baY = cy;
drawProgressBar(canvas, cTex.brewingArrowOn, cTex.brewingArrowOff,
baX, baY, brewArrowW, brewArrowH, 0.0f, false);
if (cTex.brewingStand.w > 0) {
struct nk_image standImg = slotToNkImage(cTex.brewingStand);
float bsX = cx + (igw - standW) * 0.5f;
float bsY = cy;
nk_draw_image(canvas, nk_rect(bsX, bsY, standW, standH), &standImg, nk_rgb(255, 255, 255));
}
float bottlesY = cy + standH - slotSz * 0.5f;
float bottleSpacing = slotSz + pad * 3.0f;
float bottlesRowW = 3.0f * slotSz + 2.0f * pad * 3.0f;
float bottlesStartX = cx + (igw - bottlesRowW) * 0.5f;
for (int i = 0; i < 3; i++) {
float bx = bottlesStartX + (float)i * bottleSpacing;
drawSlotGrid(canvas, bx, bottlesY, 1, 1, slotSz, pad, cTex);
}
cy += brewAreaH + gap * 2.0f;
drawShadowTextLeft(canvas, font, "Inventory", cx, cy);
cy += labelH + gap;
drawSlotGrid(canvas, cx, cy, 9, 3, slotSz, pad, cTex);
cy += igh3 + gap;
drawSlotGrid(canvas, cx, cy, 9, 1, slotSz, pad, cTex);
drawControllerPrompts(ctx, winW, winH, tex);
}
nk_end(ctx);
popCleanStyle(ctx);
}
void renderEnchanting(nk_context *ctx, int winW, int winH, MenuTextures &tex, ContainerMenuTextures &cTex)
{
float scaleX = (float)winW / BASE_W;
float scaleY = (float)winH / BASE_H;
float scale = scaleX < scaleY ? scaleX : scaleY;
float slotSz = SLOT_SIZE * scale;
float pad = SLOT_PAD * scale;
float panelPad = PANEL_PAD * scale;
float gap = SECTION_GAP * scale;
float labelH = LABEL_H * scale;
float igw = gridW(INV_COLS, slotSz, pad);
float igh3 = gridH(INV_ROWS, slotSz, pad);
float enchBtnW = 220.0f * scale;
float enchBtnH = 36.0f * scale;
float bookAreaW = 80.0f * scale;
float bookAreaH = enchBtnH * 3.0f + pad * 2.0f;
float enchAreaW = bookAreaW + gap + slotSz + gap + enchBtnW;
float enchAreaH = bookAreaH;
float topW = igw > enchAreaW ? igw : enchAreaW;
float totalH = labelH + gap + enchAreaH + gap * 2.0f + labelH + gap + igh3 + gap + slotSz;
float panelW = topW + panelPad * 2.0f;
float panelH = totalH + panelPad * 2.0f;
float panelX = ((float)winW - panelW) * 0.5f;
float panelY = ((float)winH - panelH) * 0.5f;
pushCleanStyle(ctx);
if (nk_begin(ctx, "EnchantingMenu", nk_rect(0, 0, (float)winW, (float)winH),
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) {
drawDirtBg(ctx, winW, winH, tex);
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
const struct nk_user_font *font = ctx->style.font;
nk_fill_rect(canvas, nk_rect(panelX, panelY, panelW, panelH), 4.0f * scale, nk_rgba(0, 0, 0, 180));
float cx = panelX + panelPad;
float cy = panelY + panelPad;
drawShadowTextCentered(canvas, font, "Enchant", cx, cy, topW);
cy += labelH + gap;
float esx = cx + (topW - enchAreaW) * 0.5f;
nk_fill_rect(canvas, nk_rect(esx, cy, bookAreaW, bookAreaH), 2.0f * scale, nk_rgba(40, 20, 10, 200));
float slotX = esx + bookAreaW + gap;
float slotY = cy + (bookAreaH - slotSz) * 0.5f;
if (cTex.enchantSlot.w > 0) {
struct nk_image img = slotToNkImage(cTex.enchantSlot);
nk_draw_image(canvas, nk_rect(slotX, slotY, slotSz, slotSz), &img, nk_rgb(255, 255, 255));
} else {
drawSlotGrid(canvas, slotX, slotY, 1, 1, slotSz, pad, cTex);
}
float btnX = slotX + slotSz + gap;
for (int i = 0; i < 3; i++) {
float btnY = cy + (float)i * (enchBtnH + pad);
const MenuTextureSlot *btnSlot = &cTex.enchantBtnEmpty;
if (i == 0)
btnSlot = &cTex.enchantBtnActive;
if (btnSlot->w > 0) {
struct nk_image img = slotToNkImage(*btnSlot);
nk_draw_image(canvas, nk_rect(btnX, btnY, enchBtnW, enchBtnH), &img, nk_rgb(255, 255, 255));
} else {
nk_fill_rect(canvas, nk_rect(btnX, btnY, enchBtnW, enchBtnH), 2.0f * scale, nk_rgb(60, 40, 30));
}
}
cy += enchAreaH + gap * 2.0f;
float invX = cx + (topW - igw) * 0.5f;
drawShadowTextLeft(canvas, font, "Inventory", invX, cy);
cy += labelH + gap;
drawSlotGrid(canvas, invX, cy, 9, 3, slotSz, pad, cTex);
cy += igh3 + gap;
drawSlotGrid(canvas, invX, cy, 9, 1, slotSz, pad, cTex);
drawControllerPrompts(ctx, winW, winH, tex);
}
nk_end(ctx);
popCleanStyle(ctx);
}
void renderTrading(nk_context *ctx, int winW, int winH, MenuTextures &tex, ContainerMenuTextures &cTex)
{
float scaleX = (float)winW / BASE_W;
float scaleY = (float)winH / BASE_H;
float scale = scaleX < scaleY ? scaleX : scaleY;
float slotSz = SLOT_SIZE * scale;
float pad = SLOT_PAD * scale;
float panelPad = PANEL_PAD * scale;
float gap = SECTION_GAP * scale;
float labelH = LABEL_H * scale;
float igw = gridW(INV_COLS, slotSz, pad);
float igh3 = gridH(INV_ROWS, slotSz, pad);
int tradeDisplayCount = 4;
float tradeListW = (float)tradeDisplayCount * (slotSz + pad) - pad;
float arrowW = 32.0f * scale;
float arrowH = 20.0f * scale;
float reqRowW = slotSz + gap + slotSz + gap + arrowW + gap + slotSz;
float topW = igw;
float totalH = labelH + gap + slotSz + gap + labelH + gap + slotSz
+ gap * 2.0f + labelH + gap + igh3 + gap + slotSz;
float panelW = topW + panelPad * 2.0f;
float panelH = totalH + panelPad * 2.0f;
float panelX = ((float)winW - panelW) * 0.5f;
float panelY = ((float)winH - panelH) * 0.5f;
pushCleanStyle(ctx);
if (nk_begin(ctx, "TradingMenu", nk_rect(0, 0, (float)winW, (float)winH),
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) {
drawDirtBg(ctx, winW, winH, tex);
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
const struct nk_user_font *font = ctx->style.font;
nk_fill_rect(canvas, nk_rect(panelX, panelY, panelW, panelH), 4.0f * scale, nk_rgba(0, 0, 0, 180));
float cx = panelX + panelPad;
float cy = panelY + panelPad;
drawShadowTextCentered(canvas, font, "Villager", cx, cy, topW);
cy += labelH + gap;
float tradeListX = cx + (topW - tradeListW) * 0.5f;
for (int i = 0; i < tradeDisplayCount; i++) {
float tx = tradeListX + (float)i * (slotSz + pad);
drawSlotGrid(canvas, tx, cy, 1, 1, slotSz, pad, cTex);
}
cy += slotSz + gap;
drawShadowTextLeft(canvas, font, "Required Items for Trade", cx, cy);
cy += labelH + gap;
float rsx = cx + (topW - reqRowW) * 0.5f;
drawSlotGrid(canvas, rsx, cy, 1, 1, slotSz, pad, cTex);
float r2x = rsx + slotSz + gap;
drawSlotGrid(canvas, r2x, cy, 1, 1, slotSz, pad, cTex);
float axPos = r2x + slotSz + gap;
float ayPos = cy + (slotSz - arrowH) * 0.5f;
if (cTex.arrowOff.w > 0) {
struct nk_image img = slotToNkImage(cTex.arrowOff);
nk_draw_image(canvas, nk_rect(axPos, ayPos, arrowW, arrowH), &img, nk_rgb(255, 255, 255));
}
float resX = axPos + arrowW + gap;
drawSlotGrid(canvas, resX, cy, 1, 1, slotSz, pad, cTex);
cy += slotSz + gap * 2.0f;
drawShadowTextLeft(canvas, font, "Inventory", cx, cy);
cy += labelH + gap;
drawSlotGrid(canvas, cx, cy, 9, 3, slotSz, pad, cTex);
cy += igh3 + gap;
drawSlotGrid(canvas, cx, cy, 9, 1, slotSz, pad, cTex);
drawControllerPrompts(ctx, winW, winH, tex);
}
nk_end(ctx);
popCleanStyle(ctx);
}
void renderDispenser(nk_context *ctx, int winW, int winH, MenuTextures &tex, ContainerMenuTextures &cTex)
{
float scaleX = (float)winW / BASE_W;
float scaleY = (float)winH / BASE_H;
float scale = scaleX < scaleY ? scaleX : scaleY;
float slotSz = SLOT_SIZE * scale;
float pad = SLOT_PAD * scale;
float panelPad = PANEL_PAD * scale;
float gap = SECTION_GAP * scale;
float labelH = LABEL_H * scale;
float igw = gridW(INV_COLS, slotSz, pad);
float igh3 = gridH(INV_ROWS, slotSz, pad);
float dispW = gridW(3.0f, slotSz, pad);
float dispH = gridH(3.0f, slotSz, pad);
float topW = igw;
float totalH = labelH + gap + dispH + gap * 2.0f + labelH + gap + igh3 + gap + slotSz;
float panelW = topW + panelPad * 2.0f;
float panelH = totalH + panelPad * 2.0f;
float panelX = ((float)winW - panelW) * 0.5f;
float panelY = ((float)winH - panelH) * 0.5f;
pushCleanStyle(ctx);
if (nk_begin(ctx, "DispenserMenu", nk_rect(0, 0, (float)winW, (float)winH),
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) {
drawDirtBg(ctx, winW, winH, tex);
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
const struct nk_user_font *font = ctx->style.font;
nk_fill_rect(canvas, nk_rect(panelX, panelY, panelW, panelH), 4.0f * scale, nk_rgba(0, 0, 0, 180));
float cx = panelX + panelPad;
float cy = panelY + panelPad;
drawShadowTextCentered(canvas, font, "Dispenser", cx, cy, topW);
cy += labelH + gap;
float dispX = cx + (topW - dispW) * 0.5f;
drawSlotGrid(canvas, dispX, cy, 3, 3, slotSz, pad, cTex);
cy += dispH + gap * 2.0f;
drawShadowTextLeft(canvas, font, "Inventory", cx, cy);
cy += labelH + gap;
float invX = cx + (topW - igw) * 0.5f;
drawSlotGrid(canvas, invX, cy, 9, 3, slotSz, pad, cTex);
cy += igh3 + gap;
drawSlotGrid(canvas, invX, cy, 9, 1, slotSz, pad, cTex);
drawControllerPrompts(ctx, winW, winH, tex);
}
nk_end(ctx);
popCleanStyle(ctx);
}
}}