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

374 lines
13 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 "NkScrollingMenus.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 CREDITS_LINE_H = 24.0f;
static const float CREDITS_HEADING_H = 36.0f;
static const float CREDITS_SECTION_H = 48.0f;
static const float CREDITS_SCROLL_SPEED = 40.0f;
static const float CREDITS_FAST_SPEED = 120.0f;
static const float POEM_LINE_H = 28.0f;
static const float POEM_SCROLL_SPEED = 30.0f;
static const float SHADOW_OFFSET = 2.0f;
static void drawShadowedCenteredText(nk_context *ctx, const char *text,
float x, float y, float w, float h,
struct nk_color color)
{
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
if (canvas == nullptr) return;
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;
nk_draw_text(canvas, nk_rect(textX + SHADOW_OFFSET, textY + SHADOW_OFFSET, textW, font->height),
text, len, font,
nk_rgba(0, 0, 0, 0), nk_rgba(0x0F, 0x0F, 0x0F, color.a));
nk_draw_text(canvas, nk_rect(textX, textY, textW, font->height),
text, len, font,
nk_rgba(0, 0, 0, 0), color);
}
struct CreditEntry {
const char *text;
int style;
};
static const int CREDIT_STYLE_SECTION = 0;
static const int CREDIT_STYLE_HEADING = 1;
static const int CREDIT_STYLE_NAME = 2;
static const int CREDIT_STYLE_BLANK = 3;
static const int CREDIT_STYLE_SUBHEADING = 4;
static const CreditEntry CREDIT_ENTRIES[] = {
{"MOJANG", CREDIT_STYLE_SECTION},
{"", CREDIT_STYLE_BLANK},
{"Original Design", CREDIT_STYLE_HEADING},
{"Markus Persson", CREDIT_STYLE_NAME},
{"", CREDIT_STYLE_BLANK},
{"Project Manager / Producer", CREDIT_STYLE_HEADING},
{"Daniel Kaplan", CREDIT_STYLE_NAME},
{"", CREDIT_STYLE_BLANK},
{"Rest of Mojang", CREDIT_STYLE_SUBHEADING},
{"Lead PC Developer", CREDIT_STYLE_HEADING},
{"Jens Bergensten", CREDIT_STYLE_NAME},
{"Jon Kagstrom", CREDIT_STYLE_NAME},
{"CEO", CREDIT_STYLE_HEADING},
{"Carl Manneh", CREDIT_STYLE_NAME},
{"Director of Fun", CREDIT_STYLE_HEADING},
{"Lydia Winters", CREDIT_STYLE_NAME},
{"Web Content Writer", CREDIT_STYLE_HEADING},
{"Karin Severinsson", CREDIT_STYLE_NAME},
{"Customer Support", CREDIT_STYLE_HEADING},
{"Marc Watson", CREDIT_STYLE_NAME},
{"", CREDIT_STYLE_BLANK},
{"Design & Programming", CREDIT_STYLE_HEADING},
{"Aron Nieminen", CREDIT_STYLE_NAME},
{"", CREDIT_STYLE_BLANK},
{"Chief Architect", CREDIT_STYLE_HEADING},
{"Daniel Frisk", CREDIT_STYLE_NAME},
{"Code Ninja", CREDIT_STYLE_HEADING},
{"Tobias Mollstam", CREDIT_STYLE_NAME},
{"Office DJ", CREDIT_STYLE_HEADING},
{"Kristoffer Jelbring", CREDIT_STYLE_NAME},
{"Developer", CREDIT_STYLE_HEADING},
{"Leonard Axelsson", CREDIT_STYLE_NAME},
{"Bully Coordinator", CREDIT_STYLE_HEADING},
{"Jakob Porser", CREDIT_STYLE_NAME},
{"Art Developer", CREDIT_STYLE_HEADING},
{"Junkboy", CREDIT_STYLE_NAME},
{"Explosion Animator", CREDIT_STYLE_HEADING},
{"Mattis Grahm", CREDIT_STYLE_NAME},
{"Concept Art", CREDIT_STYLE_HEADING},
{"Henrik Petterson", CREDIT_STYLE_NAME},
{"Cruncher", CREDIT_STYLE_HEADING},
{"Patrick Geuder", CREDIT_STYLE_NAME},
{"Music and Sounds", CREDIT_STYLE_HEADING},
{"Daniel Rosenfeld (C418)", CREDIT_STYLE_NAME},
{"", CREDIT_STYLE_BLANK},
{"4J Studios", CREDIT_STYLE_SECTION},
{"Programming", CREDIT_STYLE_HEADING},
{"Paddy Burns", CREDIT_STYLE_NAME},
{"Richard Reavy", CREDIT_STYLE_NAME},
{"Stuart Ross", CREDIT_STYLE_NAME},
{"James Vaughan", CREDIT_STYLE_NAME},
{"Mark Hughes", CREDIT_STYLE_NAME},
{"Harry Gordon", CREDIT_STYLE_NAME},
{"Thomas Kronberg", CREDIT_STYLE_NAME},
{"Art", CREDIT_STYLE_HEADING},
{"David Keningale", CREDIT_STYLE_NAME},
{"Alan Redmond", CREDIT_STYLE_NAME},
{"Chris Reeves", CREDIT_STYLE_NAME},
{"Kate Wright", CREDIT_STYLE_NAME},
{"Michael Hansen", CREDIT_STYLE_NAME},
{"Donald Robertson", CREDIT_STYLE_NAME},
{"Jamie Keddie", CREDIT_STYLE_NAME},
{"Thomas Naylor", CREDIT_STYLE_NAME},
{"Brian Lindsay", CREDIT_STYLE_NAME},
{"Hannah Watts", CREDIT_STYLE_NAME},
{"Rebecca O'Neil", CREDIT_STYLE_NAME},
{"QA", CREDIT_STYLE_HEADING},
{"Steven Gary Woodward", CREDIT_STYLE_NAME},
{"George Vaughan", CREDIT_STYLE_NAME},
{"", CREDIT_STYLE_BLANK},
{"Special Thanks", CREDIT_STYLE_HEADING},
{"Chris van der Kuyl", CREDIT_STYLE_NAME},
{"Roni Percy", CREDIT_STYLE_NAME},
{"Anne Clarke", CREDIT_STYLE_NAME},
{"Anthony Kent", CREDIT_STYLE_NAME},
};
static const int CREDIT_ENTRY_COUNT = sizeof(CREDIT_ENTRIES) / sizeof(CREDIT_ENTRIES[0]);
static const float CREDITS_SUBHEADING_H = 40.0f;
static float creditEntryHeight(int style, float scaleY)
{
switch (style) {
case CREDIT_STYLE_SECTION: return CREDITS_SECTION_H * scaleY;
case CREDIT_STYLE_HEADING: return CREDITS_HEADING_H * scaleY;
case CREDIT_STYLE_SUBHEADING: return CREDITS_SUBHEADING_H * scaleY;
case CREDIT_STYLE_NAME: return CREDITS_LINE_H * scaleY;
case CREDIT_STYLE_BLANK: return CREDITS_LINE_H * scaleY;
default: return CREDITS_LINE_H * scaleY;
}
}
static struct nk_color creditEntryColor(int style)
{
switch (style) {
case CREDIT_STYLE_SECTION: return nk_rgb(255, 255, 85);
case CREDIT_STYLE_HEADING: return nk_rgb(255, 170, 0);
case CREDIT_STYLE_SUBHEADING: return nk_rgb(255, 200, 50);
case CREDIT_STYLE_NAME: return nk_rgb(255, 255, 255);
default: return nk_rgba(0, 0, 0, 0);
}
}
CreditsState createCreditsState()
{
CreditsState state;
state.scrollOffset = 0.0f;
state.scrollSpeed = CREDITS_SCROLL_SPEED;
state.fastScroll = false;
return state;
}
ScrollMenuAction renderCredits(nk_context *ctx, int winW, int winH, MenuTextures &tex, CreditsState &state, float dt)
{
ScrollMenuAction result = kScrollAction_None;
float scaleY = (float)winH / BASE_H;
float speed = state.fastScroll ? CREDITS_FAST_SPEED : CREDITS_SCROLL_SPEED;
state.scrollOffset += speed * scaleY * dt;
float totalH = 0.0f;
for (int i = 0; i < CREDIT_ENTRY_COUNT; i++) {
totalH += creditEntryHeight(CREDIT_ENTRIES[i].style, scaleY);
}
totalH += (float)winH;
if (state.scrollOffset > totalH) {
result = kScrollAction_Back;
}
pushCleanStyle(ctx);
if (nk_begin(ctx, "ScrollCredits", nk_rect(0, 0, (float)winW, (float)winH),
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) {
drawDirtBg(ctx, winW, winH, tex);
drawLogo(ctx, winW, winH, tex);
float yPos = (float)winH - state.scrollOffset;
float halfW = (float)winW;
for (int i = 0; i < CREDIT_ENTRY_COUNT; i++) {
float lineH = creditEntryHeight(CREDIT_ENTRIES[i].style, scaleY);
if (yPos + lineH > 0.0f && yPos < (float)winH) {
if (CREDIT_ENTRIES[i].style != CREDIT_STYLE_BLANK) {
drawShadowedCenteredText(ctx, CREDIT_ENTRIES[i].text,
0.0f, yPos, halfW, lineH,
creditEntryColor(CREDIT_ENTRIES[i].style));
}
}
yPos += lineH;
}
const struct nk_input *input = &ctx->input;
state.fastScroll = nk_input_is_mouse_hovering_rect(input,
nk_rect(0, 0, (float)winW, (float)winH)) != 0 &&
nk_input_is_mouse_down(input, NK_BUTTON_LEFT) != 0;
if (nk_input_is_mouse_released(input, NK_BUTTON_RIGHT) != 0) {
result = kScrollAction_Back;
}
}
nk_end(ctx);
popCleanStyle(ctx);
return result;
}
static const char *END_POEM_LINES[] = {
"I see the player you mean.",
"",
"{PLAYERNAME}?",
"",
"Yes. Take care. It has reached a higher level now. It can read our thoughts.",
"",
"That doesn't matter. It thinks we are part of the game.",
"",
"I like this player. It played well. It did not give up.",
"",
"It is reading our thoughts as though they were words on a screen.",
"",
"That is how it chooses to imagine many things, when it is deep in the dream of a game.",
"",
"Words make a wonderful interface. Very flexible. And less terrifying than staring",
"at the reality behind the screen.",
"",
"They used to hear voices. Before players could read. Back in the days when those",
"who did not play called the players combatants. And disrespected them.",
"",
"And rightly so. Their game was not a good one. And what good is a game that is not good?",
"",
"Sometimes the player created worlds that were too cruel. Sometimes it created worlds that",
"were too kind. Sometimes it built a shelter against the rain. Sometimes it just played,",
"without building anything.",
"",
"And the universe said I love you.",
"",
"And the universe said you have played the game well.",
"",
"And the universe said everything you need is within you.",
"",
"And the universe said you are stronger than you know.",
"",
"And the universe said you are the daylight.",
"",
"And the universe said you are the night.",
"",
"And the universe said the darkness you fight is within you.",
"",
"And the universe said the light you seek is within you.",
"",
"And the universe said you are not alone.",
"",
"And the universe said you are not separate from every other thing.",
"",
"And the universe said you are the universe tasting itself, talking to itself, reading its own code.",
"",
"And the universe said I love you because you are love.",
"",
"And the game was over and the player woke up from the dream. And the player began a new dream.",
"And the player dreamed again, dreamed better. And the player was the universe. And the player",
"was love.",
"",
"You are the player.",
"",
"Wake up.",
};
static const int END_POEM_LINE_COUNT = sizeof(END_POEM_LINES) / sizeof(END_POEM_LINES[0]);
EndPoemState createEndPoemState()
{
EndPoemState state;
state.scrollOffset = 0.0f;
state.scrollSpeed = POEM_SCROLL_SPEED;
state.currentParagraph = 0;
return state;
}
ScrollMenuAction renderEndPoem(nk_context *ctx, int winW, int winH, MenuTextures &tex, EndPoemState &state, float dt)
{
ScrollMenuAction result = kScrollAction_None;
float scaleY = (float)winH / BASE_H;
state.scrollOffset += state.scrollSpeed * scaleY * dt;
float lineH = POEM_LINE_H * scaleY;
float totalH = (float)END_POEM_LINE_COUNT * lineH + (float)winH;
if (state.scrollOffset > totalH) {
result = kScrollAction_Back;
}
pushCleanStyle(ctx);
if (nk_begin(ctx, "ScrollEndPoem", nk_rect(0, 0, (float)winW, (float)winH),
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) {
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
if (canvas != nullptr) {
nk_fill_rect(canvas, nk_rect(0, 0, (float)winW, (float)winH), 0, nk_rgb(0, 0, 0));
}
float yPos = (float)winH - state.scrollOffset;
float textPadX = 100.0f * ((float)winW / BASE_W);
float textAreaW = (float)winW - textPadX * 2.0f;
int paragraph = 0;
for (int i = 0; i < END_POEM_LINE_COUNT; i++) {
if (yPos + lineH > 0.0f && yPos < (float)winH) {
if (strlen(END_POEM_LINES[i]) > 0) {
struct nk_color color;
if (paragraph % 2 == 0) {
color = nk_rgb(170, 170, 255);
} else {
color = nk_rgb(170, 255, 170);
}
drawShadowedCenteredText(ctx, END_POEM_LINES[i],
textPadX, yPos, textAreaW, lineH,
color);
}
}
if (strlen(END_POEM_LINES[i]) == 0) {
paragraph++;
}
yPos += lineH;
}
const struct nk_input *input = &ctx->input;
if (nk_input_is_mouse_released(input, NK_BUTTON_RIGHT) != 0) {
result = kScrollAction_Back;
}
}
nk_end(ctx);
popCleanStyle(ctx);
return result;
}
}}