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

504 lines
18 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 "NkCommon.h"
#include "MenuScreens.h"
#include "NuklearBridge.h"
#include <cstring>
#include <cstdio>
#include <cmath>
namespace lve { namespace ui {
struct nk_image slotToNkImage(const MenuTextureSlot &slot)
{
return nk_image_id(slot.id);
}
void pushCleanStyle(nk_context *ctx)
{
nk_style_push_style_item(ctx, &ctx->style.window.fixed_background, nk_style_item_hide());
nk_style_push_float(ctx, &ctx->style.window.border, 0);
nk_style_push_vec2(ctx, &ctx->style.window.padding, nk_vec2(0, 0));
nk_style_push_vec2(ctx, &ctx->style.window.spacing, nk_vec2(0, 0));
}
void popCleanStyle(nk_context *ctx)
{
nk_style_pop_vec2(ctx);
nk_style_pop_vec2(ctx);
nk_style_pop_float(ctx);
nk_style_pop_style_item(ctx);
}
void drawDirtBg(nk_context *ctx, int winW, int winH, MenuTextures &tex)
{
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
if (canvas == nullptr) return;
if (tex.dirtTile.w <= 0 || tex.dirtTile.h <= 0) {
nk_fill_rect(canvas, nk_rect(0, 0, (float)winW, (float)winH), 0, nk_rgb(59, 42, 30));
return;
}
struct nk_image dirtImg = slotToNkImage(tex.dirtTile);
float tileW = (float)tex.dirtTile.w * 2.0f;
float tileH = (float)tex.dirtTile.h * 2.0f;
for (float y = 0; y < (float)winH; y += tileH) {
for (float x = 0; x < (float)winW; x += tileW) {
float dw = (x + tileW > (float)winW) ? (float)winW - x : tileW;
float dh = (y + tileH > (float)winH) ? (float)winH - y : tileH;
nk_draw_image(canvas, nk_rect(x, y, dw, dh), &dirtImg, nk_rgb(128, 128, 128));
}
}
nk_fill_rect(canvas, nk_rect(0, 0, (float)winW, (float)winH), 0, nk_rgba(0, 0, 0, 80));
}
void drawDirtOverlay(nk_context *ctx, int winW, int winH)
{
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
if (canvas == nullptr) return;
nk_fill_rect(canvas, nk_rect(0, 0, (float)winW, (float)winH), 0, nk_rgba(0, 0, 0, 80));
}
void drawPanoramaBg(nk_context *ctx, int winW, int winH, MenuTextures &tex)
{
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
if (canvas == nullptr) return;
float w = (float)winW;
float h = (float)winH;
if (tex.panorama.w > 0 && tex.panorama.h > 0) {
struct nk_image img = slotToNkImage(tex.panorama);
float imgW = (float)tex.panorama.w;
float imgH = (float)tex.panorama.h;
float drawH = h;
float drawW = drawH * (imgW / imgH);
static float scrollX = 0.0f;
scrollX += 0.3f;
if (scrollX >= drawW) scrollX -= drawW;
float drawY = (h - drawH) * 0.5f;
float x1 = -scrollX;
nk_draw_image(canvas, nk_rect(x1, drawY, drawW, drawH), &img, nk_rgb(255, 255, 255));
nk_draw_image(canvas, nk_rect(x1 + drawW, drawY, drawW, drawH), &img, nk_rgb(255, 255, 255));
} else {
nk_fill_rect(canvas, nk_rect(0, 0, w, h), 0, nk_rgb(30, 30, 40));
}
}
void drawLogo(nk_context *ctx, int winW, int winH, MenuTextures &tex)
{
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
if (canvas == nullptr || tex.logo.w <= 0) return;
float scaleX = (float)winW / 1280.0f;
float scaleY = (float)winH / 720.0f;
float containerY = 56.0f * scaleY;
float containerW = 1280.0f * scaleX;
float containerH = 138.0f * scaleY;
float nativeW = (float)tex.logo.w;
float nativeH = (float)tex.logo.h;
float nativeAR = nativeW / nativeH;
float drawH = containerH;
float drawW = drawH * nativeAR;
if (drawW > containerW) {
drawW = containerW;
drawH = drawW / nativeAR;
}
float logoX = (containerW - drawW) * 0.5f;
float logoY = containerY + (containerH - drawH) * 0.5f;
struct nk_image logoImg = slotToNkImage(tex.logo);
nk_draw_image(canvas, nk_rect(logoX, logoY, drawW, drawH), &logoImg, nk_rgb(255, 255, 255));
}
static float shadowOff(int winH)
{
return (winH > 1080) ? 2.0f : 1.0f;
}
void drawTextWithShadow(nk_context *ctx, const char *text,
float x, float y, float maxW, int winH,
const struct nk_user_font *fontOverride)
{
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
if (canvas == nullptr) return;
const struct nk_user_font *font = fontOverride ? fontOverride : ctx->style.font;
if (font == nullptr) return;
int len = (int)strlen(text);
float off = shadowOff(winH);
nk_draw_text(canvas, nk_rect(x + off, y + off, maxW, font->height),
text, len, font,
nk_rgba(0, 0, 0, 0), nk_rgb(15, 15, 15));
nk_draw_text(canvas, nk_rect(x, y, maxW, font->height),
text, len, font,
nk_rgba(0, 0, 0, 0), nk_rgb(235, 235, 235));
}
void drawControllerPrompts(nk_context *ctx, int winW, int winH, MenuTextures &tex)
{
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
if (canvas == nullptr) return;
nk_font *smallNkFont = getSmallFont();
const struct nk_user_font *font = smallNkFont ? &smallNkFont->handle : ctx->style.font;
if (font == nullptr) return;
float iconSize = 28.0f;
float padding = 12.0f;
float promptY = (float)winH - iconSize - padding;
float curX = padding;
if (tex.controllerA.w > 0) {
struct nk_image aImg = slotToNkImage(tex.controllerA);
nk_draw_image(canvas, nk_rect(curX, promptY, iconSize, iconSize),
&aImg, nk_rgb(255, 255, 255));
curX += iconSize + 4.0f;
}
const char *selectText = "Select";
int slen = (int)strlen(selectText);
float selectW = font->width(font->userdata, font->height, selectText, slen);
float textY = promptY + (iconSize - font->height) * 0.5f;
drawTextWithShadow(ctx, selectText, curX, textY, selectW, winH, font);
curX += selectW + 16.0f;
if (tex.controllerB.w > 0) {
struct nk_image bImg = slotToNkImage(tex.controllerB);
nk_draw_image(canvas, nk_rect(curX, promptY, iconSize, iconSize),
&bImg, nk_rgb(255, 255, 255));
curX += iconSize + 4.0f;
}
const char *backText = "Back";
int blen = (int)strlen(backText);
float backW = font->width(font->userdata, font->height, backText, blen);
drawTextWithShadow(ctx, backText, curX, textY, backW, winH, font);
}
bool drawBtn(nk_context *ctx, const char *label,
float x, float y, float w, float h,
bool isHovered, int winH, MenuTextures &tex)
{
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
if (canvas == nullptr) return false;
struct nk_rect btnRect = nk_rect(x, y, w, h);
if (tex.buttonNormal.w > 0) {
if (isHovered && tex.buttonOutline.w > 0) {
struct nk_image outlineImg = slotToNkImage(tex.buttonOutline);
float padX = 3.0f * (w / 600.0f);
float padY = 3.0f * (h / 60.0f);
struct nk_rect outlineRect = nk_rect(x - padX, y - padY,
w + padX * 2.0f, h + padY * 2.0f);
nk_draw_image(canvas, outlineRect, &outlineImg, nk_rgb(255, 255, 255));
}
struct nk_image img = isHovered
? slotToNkImage(tex.buttonHover)
: slotToNkImage(tex.buttonNormal);
nk_draw_image(canvas, btnRect, &img, nk_rgb(255, 255, 255));
} else {
struct nk_color bg = isHovered ? nk_rgb(80, 80, 80) : nk_rgb(50, 50, 50);
nk_fill_rect(canvas, btnRect, 0, bg);
nk_stroke_rect(canvas, btnRect, 0, 1.0f, nk_rgb(100, 100, 100));
}
const struct nk_user_font *font = ctx->style.font;
if (font != nullptr) {
int len = (int)strlen(label);
float textW = font->width(font->userdata, font->height, label, len);
float textX = x + (w - textW) * 0.5f;
float textY = y + (h - font->height) * 0.5f;
drawTextWithShadow(ctx, label, textX, textY, textW, winH, nullptr);
}
const struct nk_input *input = &ctx->input;
bool hovering = nk_input_is_mouse_hovering_rect(input, btnRect) != 0;
bool clicked = hovering && nk_input_is_mouse_released(input, NK_BUTTON_LEFT) != 0;
return clicked;
}
void drawTitle(nk_context *ctx, const char *title, int winW, int winH,
float titleY, float titleH)
{
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
if (canvas == nullptr) return;
nk_font *titleNkFont = getTitleFont();
const struct nk_user_font *font = titleNkFont ? &titleNkFont->handle : ctx->style.font;
if (font == nullptr) return;
float scaleY = (float)winH / 720.0f;
float y = titleY * scaleY;
float h = titleH * scaleY;
int len = (int)strlen(title);
float textW = font->width(font->userdata, font->height, title, len);
float textX = ((float)winW - textW) * 0.5f;
float textY = y + (h - font->height) * 0.5f;
drawTextWithShadow(ctx, title, textX, textY, textW, winH, font);
}
void drawCenteredText(nk_context *ctx, const char *text,
float x, float y, float w, float h,
int winH)
{
const struct nk_user_font *font = ctx->style.font;
if (font == nullptr) return;
int len = (int)strlen(text);
float textW = font->width(font->userdata, font->height, text, len);
float textX = x + (w - textW) * 0.5f;
float textY = y + (h - font->height) * 0.5f;
drawTextWithShadow(ctx, text, textX, textY, textW, winH, nullptr);
}
void drawLabel(nk_context *ctx, const char *text,
float x, float y, float w, int winH)
{
drawTextWithShadow(ctx, text, x, y, w, winH, nullptr);
}
void drawLabelCentered(nk_context *ctx, const char *text,
float x, float y, float w, float h,
int winH)
{
drawCenteredText(ctx, text, x, y, w, h, winH);
}
bool drawTextInput(nk_context *ctx, const char *content,
float x, float y, float w, float h,
bool selected, int winH)
{
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
if (canvas == nullptr) return false;
struct nk_rect fieldRect = nk_rect(x, y, w, h);
nk_fill_rect(canvas, fieldRect, 0, nk_rgb(0, 0, 0));
if (selected) {
nk_stroke_rect(canvas, fieldRect, 0, 2.0f, nk_rgb(160, 160, 255));
} else {
nk_stroke_rect(canvas, fieldRect, 0, 1.0f, nk_rgb(160, 160, 160));
}
const struct nk_user_font *font = ctx->style.font;
if (font != nullptr) {
float textX = x + 6.0f;
float textY = y + (h - font->height) * 0.5f;
float maxW = w - 12.0f;
drawTextWithShadow(ctx, content, textX, textY, maxW, winH, nullptr);
if (selected) {
int len = (int)strlen(content);
float caretX = textX + font->width(font->userdata, font->height, content, len);
if (caretX > x + w - 8.0f) caretX = x + w - 8.0f;
nk_stroke_line(canvas, caretX, y + 4.0f, caretX, y + h - 4.0f,
1.0f, nk_rgb(255, 255, 255));
}
}
const struct nk_input *input = &ctx->input;
bool hovering = nk_input_is_mouse_hovering_rect(input, fieldRect) != 0;
bool clicked = hovering && nk_input_is_mouse_released(input, NK_BUTTON_LEFT) != 0;
return clicked;
}
bool drawListItem(nk_context *ctx, const char *label,
float x, float y, float w, float h,
bool selected, bool isHovered, int winH)
{
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
if (canvas == nullptr) return false;
struct nk_rect itemRect = nk_rect(x, y, w, h);
if (selected) {
nk_fill_rect(canvas, itemRect, 0, nk_rgb(60, 60, 100));
} else if (isHovered) {
nk_fill_rect(canvas, itemRect, 0, nk_rgb(50, 50, 70));
} else {
nk_fill_rect(canvas, itemRect, 0, nk_rgb(30, 30, 30));
}
nk_stroke_rect(canvas, itemRect, 0, 1.0f, nk_rgb(80, 80, 80));
const struct nk_user_font *font = ctx->style.font;
if (font != nullptr) {
float textX = x + 8.0f;
float textY = y + (h - font->height) * 0.5f;
drawTextWithShadow(ctx, label, textX, textY, w - 16.0f, winH, nullptr);
}
const struct nk_input *input = &ctx->input;
bool hovering = nk_input_is_mouse_hovering_rect(input, itemRect) != 0;
bool clicked = hovering && nk_input_is_mouse_released(input, NK_BUTTON_LEFT) != 0;
return clicked;
}
bool drawCheckbox(nk_context *ctx, const char *label,
float x, float y, float rowW, float rowH,
bool checked, bool /*enabled*/, int winH, MenuTextures &tex)
{
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
if (canvas == nullptr) return checked;
const struct nk_input *input = &ctx->input;
const struct nk_user_font *font = ctx->style.font;
float cbSize = rowH * 0.75f;
float cbX = x;
float cbY = y + (rowH - cbSize) * 0.5f;
struct nk_rect fullRect = nk_rect(x, y, rowW, rowH);
bool hovering = nk_input_is_mouse_hovering_rect(input, fullRect) != 0;
if (tex.checkboxBackground.w > 0) {
struct nk_image bgImg = slotToNkImage(hovering ? tex.checkboxHover : tex.checkboxBackground);
nk_draw_image(canvas, nk_rect(cbX, cbY, cbSize, cbSize), &bgImg, nk_rgb(255, 255, 255));
} else {
nk_fill_rect(canvas, nk_rect(cbX, cbY, cbSize, cbSize), 0, nk_rgb(40, 40, 40));
nk_stroke_rect(canvas, nk_rect(cbX, cbY, cbSize, cbSize), 0, 1.0f,
hovering ? nk_rgb(180, 180, 200) : nk_rgb(120, 120, 120));
}
if (checked && tex.checkboxTick.w > 0) {
struct nk_image tickImg = slotToNkImage(tex.checkboxTick);
nk_draw_image(canvas, nk_rect(cbX, cbY, cbSize, cbSize), &tickImg, nk_rgb(255, 255, 255));
} else if (checked) {
float inset = cbSize * 0.2f;
nk_fill_rect(canvas, nk_rect(cbX + inset, cbY + inset,
cbSize - 2.0f * inset, cbSize - 2.0f * inset),
0, nk_rgb(255, 255, 255));
}
if (font != nullptr) {
float textX = cbX + cbSize + 8.0f;
float textY = y + (rowH - font->height) * 0.5f;
drawTextWithShadow(ctx, label, textX, textY, rowW - cbSize - 8.0f, winH, nullptr);
}
bool clicked = hovering && nk_input_is_mouse_released(input, NK_BUTTON_LEFT) != 0;
if (clicked) return !checked;
return checked;
}
int drawSlider(nk_context *ctx, const char *label,
float x, float y, float w, float h,
int value, int minVal, int maxVal,
int winH, MenuTextures &tex)
{
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
if (canvas == nullptr) return value;
const struct nk_input *input = &ctx->input;
const struct nk_user_font *font = ctx->style.font;
if (tex.sliderBackground.w > 0) {
struct nk_image bgImg = slotToNkImage(tex.sliderBackground);
nk_draw_image(canvas, nk_rect(x, y, w, h), &bgImg, nk_rgb(255, 255, 255));
} else {
nk_fill_rect(canvas, nk_rect(x, y, w, h), 0, nk_rgb(30, 30, 30));
nk_stroke_rect(canvas, nk_rect(x, y, w, h), 0, 1.0f, nk_rgb(80, 80, 80));
}
float inset = 6.0f;
float innerX = x + inset;
float innerW = w - inset * 2.0f;
float innerY = y + inset;
float innerH = h - inset * 2.0f;
float range = (float)(maxVal - minVal);
float ratio = (range > 0.0f) ? (float)(value - minVal) / range : 0.0f;
if (ratio < 0.0f) ratio = 0.0f;
if (ratio > 1.0f) ratio = 1.0f;
float filledW = innerW * ratio;
if (filledW > 0.0f) {
if (tex.sliderTrackActive.w > 0) {
struct nk_image activeImg = slotToNkImage(tex.sliderTrackActive);
nk_draw_image(canvas, nk_rect(innerX, innerY, filledW, innerH),
&activeImg, nk_rgb(255, 255, 255));
} else {
nk_fill_rect(canvas, nk_rect(innerX, innerY, filledW, innerH),
0, nk_rgb(76, 175, 80));
}
}
float unfilledW = innerW - filledW;
if (unfilledW > 0.0f) {
if (tex.sliderTrackInactive.w > 0) {
struct nk_image inactiveImg = slotToNkImage(tex.sliderTrackInactive);
nk_draw_image(canvas, nk_rect(innerX + filledW, innerY, unfilledW, innerH),
&inactiveImg, nk_rgb(255, 255, 255));
} else {
nk_fill_rect(canvas, nk_rect(innerX + filledW, innerY, unfilledW, innerH),
0, nk_rgb(60, 60, 60));
}
}
float thumbW = 16.0f;
float thumbX = innerX + filledW - thumbW * 0.5f;
if (thumbX < innerX) thumbX = innerX;
if (thumbX + thumbW > innerX + innerW) thumbX = innerX + innerW - thumbW;
if (tex.sliderThumb.w > 0) {
struct nk_image thumbImg = slotToNkImage(tex.sliderThumb);
nk_draw_image(canvas, nk_rect(thumbX, y, thumbW, h),
&thumbImg, nk_rgb(255, 255, 255));
} else {
nk_fill_rect(canvas, nk_rect(thumbX, y, thumbW, h),
0, nk_rgb(200, 200, 200));
}
if (font != nullptr) {
int len = (int)strlen(label);
float textW = font->width(font->userdata, font->height, label, len);
float textX = x + (w - textW) * 0.5f;
float textY = y + (h - font->height) * 0.5f;
drawTextWithShadow(ctx, label, textX, textY, textW, winH, nullptr);
}
struct nk_rect sliderRect = nk_rect(x, y, w, h);
bool hovering = nk_input_is_mouse_hovering_rect(input, sliderRect) != 0;
bool held = nk_input_is_mouse_down(input, NK_BUTTON_LEFT) != 0;
if (hovering && held) {
float mouseX = input->mouse.pos.x;
float newRatio = (mouseX - innerX) / innerW;
if (newRatio < 0.0f) newRatio = 0.0f;
if (newRatio > 1.0f) newRatio = 1.0f;
int newVal = minVal + (int)(newRatio * range + 0.5f);
if (newVal < minVal) newVal = minVal;
if (newVal > maxVal) newVal = maxVal;
return newVal;
}
return value;
}
}}