mirror of
https://github.com/coah80/LegacyVulkEdition.git
synced 2026-07-19 15:08:14 +00:00
321 lines
11 KiB
C++
321 lines
11 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 "NkHUD.h"
|
|
#include "NkCommon.h"
|
|
#include "NuklearBridge.h"
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <cmath>
|
|
|
|
static const float BASE_W = 1280.0f;
|
|
static const float BASE_H = 720.0f;
|
|
|
|
static const float HUD_SCALE = 3.0f;
|
|
|
|
static const float CROSSHAIR_NATIVE = 15.0f;
|
|
|
|
static const float HOLDER_X = 366.0f;
|
|
static const float HOLDER_Y = 480.0f;
|
|
|
|
static const float HOTBAR_W = 182.0f;
|
|
static const float HOTBAR_H = 22.0f;
|
|
static const int HOTBAR_SLOTS = 9;
|
|
static const float HOTBAR_SLOT_PITCH = 20.0f;
|
|
static const float HOTBAR_SLOT_PAD = 3.0f;
|
|
static const float HOTBAR_SELECTED_SIZE = 24.0f;
|
|
|
|
static const float ICON_SIZE = 9.0f;
|
|
static const float ICON_SPACING = 8.0f;
|
|
static const int ICON_ROW_COUNT = 10;
|
|
|
|
static const float XP_BAR_W = 182.0f;
|
|
static const float XP_BAR_H = 5.0f;
|
|
|
|
static const float ARMOR_Y_OFF = 0.0f;
|
|
static const float HEALTH_Y_OFF = 10.0f;
|
|
static const float XP_Y_OFF = 20.0f;
|
|
static const float HOTBAR_Y_OFF = 26.0f;
|
|
|
|
static const float LEFT_X_OFF = 0.0f;
|
|
static const float RIGHT_X_OFF = 101.0f;
|
|
static const float HOTBAR_X_OFF = 0.0f;
|
|
|
|
static const float XP_LEVEL_X_OFF = 81.0f;
|
|
static const float XP_LEVEL_Y_OFF = 10.0f;
|
|
static const float XP_LEVEL_W = 20.0f;
|
|
|
|
static struct nk_image imageFromHUD(const lve::ui::HUDTextureSlot &slot)
|
|
{
|
|
return nk_image_id(slot.id);
|
|
}
|
|
|
|
static lve::ui::HUDTextureSlot loadHUDSlot(const char *path)
|
|
{
|
|
int w = 0, h = 0;
|
|
struct nk_image img = lve::ui::loadTextureWithSize(path, &w, &h);
|
|
return {img.handle.id, w, h};
|
|
}
|
|
|
|
namespace lve { namespace ui {
|
|
|
|
bool initHUDTextures(HUDTextures &tex)
|
|
{
|
|
const char *base = "../Assets/ui/skinHDGraphicsHud/";
|
|
char path[256];
|
|
|
|
auto load = [&](const char *file) -> HUDTextureSlot {
|
|
snprintf(path, sizeof(path), "%s%s", base, file);
|
|
return loadHUDSlot(path);
|
|
};
|
|
|
|
tex.crosshair = load("27_HUD_Crosshair.png");
|
|
tex.hotbarBack = load("29_hotbar_item_back.png");
|
|
tex.hotbarSelected = load("28_hotbar_item_selected.png");
|
|
tex.healthFull = load("34_Health_Full.png");
|
|
tex.healthHalf = load("30_Health_Half.png");
|
|
tex.healthBg = load("38_Health_Background.png");
|
|
tex.foodFull = load("44_HUD_Food_Full.png");
|
|
tex.foodHalf = load("40_HUD_Food_Half.png");
|
|
tex.foodBg = load("48_HUD_Food_Background.png");
|
|
tex.armorFull = load("54_HUD_Armour_Full.png");
|
|
tex.armorHalf = load("53_HUD_Armour_Half.png");
|
|
tex.armorEmpty = load("55_HUD_Armour_Empty.png");
|
|
tex.airBubble = load("57_HUD_Air_Bubble.png");
|
|
tex.airPop = load("56_HUD_Air_Pop.png");
|
|
tex.xpBarFull = load("51_experience_bar_full.png");
|
|
tex.xpBarEmpty = load("52_experience_bar_empty.png");
|
|
|
|
tex.loaded = (tex.crosshair.w > 0 && tex.hotbarBack.w > 0 &&
|
|
tex.healthFull.w > 0 && tex.foodFull.w > 0 &&
|
|
tex.xpBarEmpty.w > 0);
|
|
|
|
if (!tex.loaded)
|
|
fprintf(stderr, "[NkHUD] WARNING: some HUD textures failed to load\n");
|
|
|
|
return tex.loaded;
|
|
}
|
|
|
|
static void drawCrosshair(struct nk_command_buffer *canvas, int winW, int winH,
|
|
const HUDTextures &tex, float sx, float sy)
|
|
{
|
|
if (tex.crosshair.w <= 0) return;
|
|
|
|
float w = CROSSHAIR_NATIVE * HUD_SCALE * sx;
|
|
float h = CROSSHAIR_NATIVE * HUD_SCALE * sy;
|
|
float x = (float)winW * 0.5f - w * 0.5f;
|
|
float y = (float)winH * 0.5f - h * 0.5f;
|
|
|
|
struct nk_image img = imageFromHUD(tex.crosshair);
|
|
nk_draw_image(canvas, nk_rect(x, y, w, h), &img, nk_rgba(255, 255, 255, 255));
|
|
}
|
|
|
|
static void drawHotbar(struct nk_command_buffer *canvas, float hx, float hy,
|
|
float sx, float sy, const HUDTextures &tex, int selected)
|
|
{
|
|
if (tex.hotbarBack.w <= 0) return;
|
|
|
|
float barX = hx + HOTBAR_X_OFF * HUD_SCALE * sx;
|
|
float barY = hy + HOTBAR_Y_OFF * HUD_SCALE * sy;
|
|
float barW = HOTBAR_W * HUD_SCALE * sx;
|
|
float barH = HOTBAR_H * HUD_SCALE * sy;
|
|
|
|
struct nk_image back = imageFromHUD(tex.hotbarBack);
|
|
nk_draw_image(canvas, nk_rect(barX, barY, barW, barH), &back, nk_rgba(255, 255, 255, 255));
|
|
|
|
if (tex.hotbarSelected.w <= 0 || selected < 0 || selected >= HOTBAR_SLOTS) return;
|
|
|
|
float selW = HOTBAR_SELECTED_SIZE * HUD_SCALE * sx;
|
|
float selH = HOTBAR_SELECTED_SIZE * HUD_SCALE * sy;
|
|
float pitch = HOTBAR_SLOT_PITCH * HUD_SCALE * sx;
|
|
float padX = HOTBAR_SLOT_PAD * HUD_SCALE * sx;
|
|
float selX = barX + padX - (2.0f * HUD_SCALE * sx) + (float)selected * pitch;
|
|
float selY = barY - (1.0f * HUD_SCALE * sy);
|
|
|
|
struct nk_image sel = imageFromHUD(tex.hotbarSelected);
|
|
nk_draw_image(canvas, nk_rect(selX, selY, selW, selH), &sel, nk_rgba(255, 255, 255, 255));
|
|
}
|
|
|
|
static void drawIconRow(struct nk_command_buffer *canvas,
|
|
float baseX, float baseY, float sx, float sy,
|
|
const HUDTextureSlot &bg, const HUDTextureSlot &full,
|
|
const HUDTextureSlot &half, int value, bool mirror)
|
|
{
|
|
float iw = ICON_SIZE * HUD_SCALE * sx;
|
|
float ih = ICON_SIZE * HUD_SCALE * sy;
|
|
float step = ICON_SPACING * HUD_SCALE * sx;
|
|
|
|
for (int i = 0; i < ICON_ROW_COUNT; i++)
|
|
{
|
|
float ix = mirror
|
|
? baseX + (float)(ICON_ROW_COUNT - 1 - i) * step
|
|
: baseX + (float)i * step;
|
|
|
|
if (bg.w > 0)
|
|
{
|
|
struct nk_image bgImg = nk_image_id(bg.id);
|
|
nk_draw_image(canvas, nk_rect(ix, baseY, iw, ih), &bgImg, nk_rgba(255, 255, 255, 255));
|
|
}
|
|
|
|
int halfPoints = i * 2;
|
|
if (halfPoints + 1 < value && full.w > 0)
|
|
{
|
|
struct nk_image fImg = nk_image_id(full.id);
|
|
nk_draw_image(canvas, nk_rect(ix, baseY, iw, ih), &fImg, nk_rgba(255, 255, 255, 255));
|
|
}
|
|
else if (halfPoints < value && half.w > 0)
|
|
{
|
|
struct nk_image hImg = nk_image_id(half.id);
|
|
nk_draw_image(canvas, nk_rect(ix, baseY, iw, ih), &hImg, nk_rgba(255, 255, 255, 255));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void drawAirBubbles(struct nk_command_buffer *canvas,
|
|
float baseX, float baseY, float sx, float sy,
|
|
const HUDTextures &tex, int bubbles)
|
|
{
|
|
float iw = ICON_SIZE * HUD_SCALE * sx;
|
|
float ih = ICON_SIZE * HUD_SCALE * sy;
|
|
float step = ICON_SPACING * HUD_SCALE * sx;
|
|
|
|
for (int i = 0; i < ICON_ROW_COUNT; i++)
|
|
{
|
|
float ix = baseX + (float)(ICON_ROW_COUNT - 1 - i) * step;
|
|
|
|
if (i < bubbles && tex.airBubble.w > 0)
|
|
{
|
|
struct nk_image img = imageFromHUD(tex.airBubble);
|
|
nk_draw_image(canvas, nk_rect(ix, baseY, iw, ih), &img, nk_rgba(255, 255, 255, 255));
|
|
}
|
|
else if (tex.airPop.w > 0)
|
|
{
|
|
struct nk_image img = imageFromHUD(tex.airPop);
|
|
nk_draw_image(canvas, nk_rect(ix, baseY, iw, ih), &img, nk_rgba(255, 255, 255, 255));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void drawXPBar(struct nk_command_buffer *canvas, float hx, float hy,
|
|
float sx, float sy, const HUDTextures &tex,
|
|
float progress, int level)
|
|
{
|
|
float barX = hx + LEFT_X_OFF * HUD_SCALE * sx;
|
|
float barY = hy + XP_Y_OFF * HUD_SCALE * sy;
|
|
float barW = XP_BAR_W * HUD_SCALE * sx;
|
|
float barH = XP_BAR_H * HUD_SCALE * sy;
|
|
|
|
if (tex.xpBarEmpty.w > 0)
|
|
{
|
|
struct nk_image empty = imageFromHUD(tex.xpBarEmpty);
|
|
nk_draw_image(canvas, nk_rect(barX, barY, barW, barH), &empty, nk_rgba(255, 255, 255, 255));
|
|
}
|
|
|
|
if (tex.xpBarFull.w > 0 && progress > 0.0f)
|
|
{
|
|
float fillW = barW * progress;
|
|
struct nk_image sub = nk_subimage_id(tex.xpBarFull.id,
|
|
(unsigned short)tex.xpBarFull.w, (unsigned short)tex.xpBarFull.h,
|
|
nk_rect(0, 0, (float)tex.xpBarFull.w * progress, (float)tex.xpBarFull.h));
|
|
nk_draw_image(canvas, nk_rect(barX, barY, fillW, barH), &sub, nk_rgba(255, 255, 255, 255));
|
|
}
|
|
|
|
if (level <= 0) return;
|
|
|
|
nk_context *ctx = getNkContext();
|
|
const struct nk_user_font *font = ctx->style.font;
|
|
if (font == nullptr) return;
|
|
|
|
char buf[16];
|
|
snprintf(buf, sizeof(buf), "%d", level);
|
|
int len = (int)strlen(buf);
|
|
float tw = font->width(font->userdata, font->height, buf, len);
|
|
|
|
float levelX = hx + XP_LEVEL_X_OFF * HUD_SCALE * sx;
|
|
float levelW = XP_LEVEL_W * HUD_SCALE * sx;
|
|
float tx = levelX + (levelW - tw) * 0.5f;
|
|
float ty = hy + XP_LEVEL_Y_OFF * HUD_SCALE * sy;
|
|
|
|
nk_draw_text(canvas, nk_rect(tx + 1, ty + 1, tw + 2, font->height),
|
|
buf, len, font, nk_rgba(0, 0, 0, 0), nk_rgba(0, 0, 0, 255));
|
|
nk_draw_text(canvas, nk_rect(tx, ty, tw, font->height),
|
|
buf, len, font, nk_rgba(0, 0, 0, 0), nk_rgba(128, 255, 32, 255));
|
|
}
|
|
|
|
void renderHUD(nk_context *ctx, int winW, int winH, HUDTextures &tex)
|
|
{
|
|
if (!tex.loaded) return;
|
|
|
|
float sx = (float)winW / BASE_W;
|
|
float sy = (float)winH / BASE_H;
|
|
|
|
pushCleanStyle(ctx);
|
|
|
|
if (nk_begin(ctx, "HUD", nk_rect(0, 0, (float)winW, (float)winH),
|
|
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT))
|
|
{
|
|
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
|
|
if (canvas == nullptr)
|
|
{
|
|
nk_end(ctx);
|
|
popCleanStyle(ctx);
|
|
return;
|
|
}
|
|
|
|
drawCrosshair(canvas, winW, winH, tex, sx, sy);
|
|
|
|
float hx = HOLDER_X * sx;
|
|
float hy = HOLDER_Y * sy;
|
|
|
|
int selectedSlot = 0;
|
|
int health = 20;
|
|
int food = 20;
|
|
int armor = 20;
|
|
int air = 10;
|
|
float xpProgress = 0.45f;
|
|
int xpLevel = 7;
|
|
bool showArmor = true;
|
|
bool showAir = false;
|
|
|
|
drawIconRow(canvas,
|
|
hx + LEFT_X_OFF * HUD_SCALE * sx,
|
|
hy + HEALTH_Y_OFF * HUD_SCALE * sy,
|
|
sx, sy, tex.healthBg, tex.healthFull, tex.healthHalf, health, false);
|
|
|
|
drawIconRow(canvas,
|
|
hx + RIGHT_X_OFF * HUD_SCALE * sx,
|
|
hy + HEALTH_Y_OFF * HUD_SCALE * sy,
|
|
sx, sy, tex.foodBg, tex.foodFull, tex.foodHalf, food, true);
|
|
|
|
if (showArmor)
|
|
{
|
|
drawIconRow(canvas,
|
|
hx + LEFT_X_OFF * HUD_SCALE * sx,
|
|
hy + ARMOR_Y_OFF * HUD_SCALE * sy,
|
|
sx, sy, tex.armorEmpty, tex.armorFull, tex.armorHalf, armor, false);
|
|
}
|
|
|
|
if (showAir)
|
|
{
|
|
drawAirBubbles(canvas,
|
|
hx + RIGHT_X_OFF * HUD_SCALE * sx,
|
|
hy + ARMOR_Y_OFF * HUD_SCALE * sy,
|
|
sx, sy, tex, air);
|
|
}
|
|
|
|
drawXPBar(canvas, hx, hy, sx, sy, tex, xpProgress, xpLevel);
|
|
drawHotbar(canvas, hx, hy, sx, sy, tex, selectedSlot);
|
|
}
|
|
nk_end(ctx);
|
|
|
|
popCleanStyle(ctx);
|
|
}
|
|
|
|
}}
|