This repository has been archived on 2022-05-21. You can view files and clone it, but cannot push or open issues or pull requests.
LEFTONE/core/loui/hud.c

320 lines
9.1 KiB
C

#include "./hud.h"
#include <assert.h>
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "util/glyphas/block.h"
#include "util/glyphas/cache.h"
#include "util/math/vector.h"
#include "core/lochara/base.h"
#include "core/locommon/easing.h"
#include "core/locommon/screen.h"
#include "core/locommon/ticker.h"
#include "core/loplayer/player.h"
#include "core/loresource/set.h"
#include "core/loresource/text.h"
#include "core/loshader/set.h"
#define BAR_SPEED_ 5
#define STATUS_MAX_WIDTH_ .6f
#define STATUS_FAITH_SIZE_ .8f
#define EFFECT_TEXT_COLOR_ vec4(1, 1, 1, 1)
#define EFFECT_FADE_SPEED_ 2
#define EFFECT_LINE_HEIGHT_ 1.2f
#define BIOME_TEXT_COLOR_ vec4(1, 1, 1, 1)
#define BIOME_TEXT_SEED_ 29 /* = prime number */
static void loui_hud_calculate_geometry_(
loui_hud_t* hud, const locommon_screen_t* screen) {
assert(hud != NULL);
assert(locommon_screen_valid(screen));
typeof(hud->geo)* g = &hud->geo;
# define inch2winpos_(winpos, inch) \
locommon_screen_calc_winpos_from_inch(screen, winpos, inch)
inch2winpos_(&g->padding, &vec2(.3f, .3f));
inch2winpos_(&g->madness_sz, &vec2(3.f, .12f));
if (g->madness_sz.x > STATUS_MAX_WIDTH_) {
vec2_muleq(&g->madness_sz, STATUS_MAX_WIDTH_/g->madness_sz.x);
}
vec2_mul(&g->faith_sz, &g->madness_sz, .5f);
# undef inch2winpos_
g->madness_pos = vec2(-1, 1);
g->madness_pos.x += g->madness_sz.x + g->padding.x;
g->madness_pos.y -= g->madness_sz.y + g->padding.y;
g->faith_pos = vec2(-1, 1);
g->faith_pos.x += g->padding.x + g->faith_sz.x;
g->faith_pos.y -= g->padding.y + g->madness_sz.y*2 + g->faith_sz.y;
locommon_screen_calc_pixels_from_inch(
screen, &g->effect_fontpx, &vec2(.4f, .4f));
locommon_screen_calc_winpos_from_pixels(
screen, &g->effect_fontsz, &g->effect_fontpx);
g->effect_sz.x = 3*screen->dpi.x/screen->resolution.x;
g->effect_sz.y = 4/screen->resolution.y;
g->effect_pos = vec2(1-g->padding.x, -1+g->padding.y);
vec2_subeq(&g->effect_pos, &g->effect_sz);
locommon_screen_calc_pixels_from_inch(
screen, &g->biome_fontpx, &vec2(.3f, .3f));
locommon_screen_calc_winpos_from_pixels(
screen, &g->biome_fontsz, &g->biome_fontpx);
vec2_add(&g->biome_pos, &vec2(-1, -1), &g->padding);
}
static void loui_hud_draw_status_bars_(const loui_hud_t* hud) {
assert(hud != NULL);
loshader_hud_bar_drawer_add_instance(
&hud->shaders->drawer.hud_bar,
&(loshader_hud_bar_drawer_instance_t) {
.pos = hud->geo.madness_pos,
.size = hud->geo.madness_sz,
.bgcolor = vec4(0, 0, 0, hud->alpha),
.fgcolor = vec4(1, 1, 1, .9f*hud->alpha),
.value = hud->player->entity->param.recipient.madness,
.prev_value = hud->prev_madness,
});
loshader_hud_bar_drawer_add_instance(
&hud->shaders->drawer.hud_bar,
&(loshader_hud_bar_drawer_instance_t) {
.pos = hud->geo.faith_pos,
.size = hud->geo.faith_sz,
.bgcolor = vec4(0, 0, 0, hud->alpha),
.fgcolor = vec4(.9f, .9f, .9f, .9f*hud->alpha),
.value = hud->player->entity->param.recipient.faith,
.prev_value = hud->prev_faith,
});
}
static void loui_hud_initialize_effect_(
loui_hud_t* hud,
loui_hud_effect_t* effect,
const locommon_screen_t* screen,
const char* name) {
assert(hud != NULL);
assert(effect != NULL);
assert(name != NULL);
assert(locommon_screen_valid(screen));
*effect = (typeof(*effect)) {
.text = glyphas_block_new(
GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL,
-hud->geo.effect_fontpx.y,
INT32_MAX,
32),
};
glyphas_block_add_characters(
effect->text, hud->font.effect, &EFFECT_TEXT_COLOR_, name, strlen(name));
const vec2_t reso = screen->resolution;
glyphas_block_scale(effect->text, &vec2(2/reso.x, 2/reso.y));
}
static void loui_hud_deinitialize_effect_(loui_hud_effect_t* effect) {
assert(effect != NULL);
glyphas_block_delete(effect->text);
}
static void loui_hud_update_effect_bars_(loui_hud_t* hud) {
assert(hud != NULL);
const loeffect_recipient_t* r = &hud->player->entity->param.recipient;
loui_hud_effect_set_t* e = &hud->effects.set;
const uint64_t t = hud->ticker->time;
const float dt = hud->ticker->delta_f;
# define lasting_effect_(n) do { \
const bool active = \
r->effects.n.start <= t && \
t < r->effects.n.start + r->effects.n.duration; \
locommon_easing_smooth_float( \
&e->n.alpha, !!active, dt*EFFECT_FADE_SPEED_); \
if (active) { \
e->n.value = (t - r->effects.n.start)*1.f / r->effects.n.duration; \
} \
} while (0)
lasting_effect_(amnesia);
lasting_effect_(curse);
# undef lasting_effect_
}
static void loui_hud_draw_effect_bars_(const loui_hud_t* hud) {
assert(hud != NULL);
const typeof(hud->geo)* g = &hud->geo;
float h = 0;
for (size_t i = 0; i < LOUI_HUD_EFFECT_COUNT; ++i) {
const loui_hud_effect_t* e = &hud->effects.arr[i];
if (e->alpha == 0) continue;
const float a = e->alpha * hud->alpha;
const float y = h*g->effect_fontsz.y + g->effect_pos.y;
glyphas_block_set_origin(e->text, &vec2(1, -1));
glyphas_block_translate(e->text, &vec2(1-g->padding.x, y));
glyphas_block_set_alpha(e->text, powf(a, 2));
loshader_hud_text_drawer_add_block(
&hud->shaders->drawer.hud_text, e->text);
loshader_hud_bar_drawer_add_instance(
&hud->shaders->drawer.hud_bar,
&(loshader_hud_bar_drawer_instance_t) {
.pos = vec2(g->effect_pos.x, y),
.size = vec2(-g->effect_sz.x, g->effect_sz.y),
.bgcolor = vec4(1, 1, 1, .2f*a),
.fgcolor = vec4(1, 1, 1, .8f*a),
.value = e->value,
.prev_value = e->value,
});
h += a*a*(3-2*a)*EFFECT_LINE_HEIGHT_;
}
}
static glyphas_block_t* loui_hud_create_biome_text_(
loui_hud_t* hud, const locommon_screen_t* screen, const char* text) {
assert(hud != NULL);
assert(text != NULL);
assert(locommon_screen_valid(screen));
glyphas_block_t* b = glyphas_block_new(
GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL,
-hud->geo.biome_fontpx.y,
INT32_MAX,
32);
glyphas_block_add_characters(
b, hud->font.biome, &BIOME_TEXT_COLOR_, text, strlen(text));
const vec2_t reso = screen->resolution;
glyphas_block_scale(b, &vec2(2/reso.x, 2/reso.y));
glyphas_block_set_origin(b, &vec2(0, -1));
glyphas_block_translate(b, &hud->geo.biome_pos);
glyphas_block_make_glitched(b, text[0]*BIOME_TEXT_SEED_);
return b;
}
static void loui_hud_draw_biome_text_(const loui_hud_t* hud) {
assert(hud != NULL);
loshader_hud_text_drawer_add_block(
&hud->shaders->drawer.hud_text, hud->biomes[hud->current_biome]);
}
void loui_hud_initialize(
loui_hud_t* hud,
loresource_set_t* res,
loshader_set_t* shaders,
const locommon_screen_t* screen,
const locommon_ticker_t* ticker,
loplayer_t* player) {
assert(hud != NULL);
assert(res != NULL);
assert(shaders != NULL);
assert(ticker != NULL);
assert(player != NULL);
assert(locommon_screen_valid(screen));
*hud = (typeof(*hud)) {
.shaders = shaders,
.ticker = ticker,
.player = player,
};
loui_hud_calculate_geometry_(hud, screen);
hud->font = (typeof(hud->font)) {
.effect = glyphas_cache_new(
shaders->tex.hud_text,
&res->font.sans,
hud->geo.effect_fontpx.x,
hud->geo.effect_fontpx.y),
.biome = glyphas_cache_new(
shaders->tex.hud_text,
&res->font.serif,
hud->geo.biome_fontpx.x,
hud->geo.biome_fontpx.y),
};
# define text_(name) loresource_text_get(res->lang, name)
loui_hud_effect_set_t* e = &hud->effects.set;
loui_hud_initialize_effect_(
hud, &e->amnesia, screen, text_("effect_amnesia"));
loui_hud_initialize_effect_(
hud, &e->curse, screen, text_("effect_curse"));
# define each_(NAME, name) do { \
hud->biomes[LOWORLD_CHUNK_BIOME_##NAME] = \
loui_hud_create_biome_text_(hud, screen, text_("biome_"#name)); \
} while (0)
LOWORLD_CHUNK_BIOME_EACH(each_);
# undef each_
# undef text_
}
void loui_hud_deinitialize(loui_hud_t* hud) {
assert(hud != NULL);
for (size_t i = 0; i < LOUI_HUD_EFFECT_COUNT; ++i) {
loui_hud_deinitialize_effect_(&hud->effects.arr[i]);
}
for (size_t i = 0; i < LOWORLD_CHUNK_BIOME_COUNT; ++i) {
glyphas_block_delete(hud->biomes[i]);
}
glyphas_cache_delete(hud->font.effect);
glyphas_cache_delete(hud->font.biome);
}
void loui_hud_update(loui_hud_t* hud) {
assert(hud != NULL);
const float dt = hud->ticker->delta_f;
locommon_easing_smooth_float(
&hud->prev_madness,
hud->player->entity->param.recipient.madness,
dt*BAR_SPEED_);
locommon_easing_smooth_float(
&hud->prev_faith, hud->player->entity->param.recipient.faith,
dt*BAR_SPEED_);
loui_hud_update_effect_bars_(hud);
}
void loui_hud_draw(const loui_hud_t* hud) {
assert(hud != NULL);
hud->shaders->drawer.hud_text.alpha = hud->alpha;
loui_hud_draw_status_bars_(hud);
loui_hud_draw_effect_bars_(hud);
loui_hud_draw_biome_text_(hud);
}