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/loplayer/hud.c

410 lines
11 KiB
C
Raw Normal View History

#include "./hud.h"
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "util/conv/charcode.h"
#include "util/glyphas/block.h"
#include "util/glyphas/cache.h"
#include "util/math/algorithm.h"
#include "util/memory/memory.h"
#include "core/locommon/easing.h"
#include "core/locommon/position.h"
#include "core/locommon/ticker.h"
#include "core/loresource/set.h"
#include "core/loresource/text.h"
#include "core/loshader/hud_bar.h"
#include "core/loshader/set.h"
#include "./entity.h"
#include "./event.h"
#include "./status.h"
typedef struct {
float alpha;
float remain;
glyphas_block_t* text;
} loplayer_hud_effect_t;
struct loplayer_hud_t {
/* injected deps */
loshader_set_t* shaders;
const locommon_ticker_t* ticker;
const loplayer_event_t* event;
const loplayer_status_t* status;
const loplayer_entity_t* entity;
/* owned objects */
struct {
glyphas_cache_t* sans;
glyphas_cache_t* serif;
} font;
/* immutable params */
struct {
vec2_t fontsz_normal_px;
vec2_t fontsz_normal;
vec2_t fontsz_small_px;
vec2_t fontsz_small;
vec2_t padding;
vec2_t madness_bar_pos;
vec2_t madness_bar_size;
vec2_t faith_bar_pos;
vec2_t faith_bar_size;
vec2_t effect_bar_pos;
vec2_t effect_bar_size;
} geometry;
/* mutable params */
float alpha;
float prev_madness;
float prev_faith;
bool shown;
glyphas_block_t* biome_text;
union {
struct {
loplayer_hud_effect_t curse;
loplayer_hud_effect_t amnesia;
loplayer_hud_effect_t lost;
};
loplayer_hud_effect_t array[3];
} effects;
};
static void loplayer_hud_calculate_geometry_(loplayer_hud_t* hud) {
assert(hud != NULL);
const vec2_t* dpi = &hud->shaders->dpi;
const vec2_t* reso = &hud->shaders->resolution;
typeof(hud->geometry)* geo = &hud->geometry;
# define px_to_disp_(v) vec2((v).x/reso->x*2, (v).y/reso->y*2)
geo->fontsz_normal_px = *dpi;
vec2_muleq(&geo->fontsz_normal_px, .4f);
geo->fontsz_normal = px_to_disp_(geo->fontsz_normal_px);
geo->fontsz_small_px = *dpi;
vec2_muleq(&geo->fontsz_small_px, .3f);
geo->fontsz_small = px_to_disp_(geo->fontsz_small_px);
geo->padding = *dpi;
vec2_muleq(&geo->padding, .4f);
geo->padding = px_to_disp_(geo->padding);
geo->madness_bar_size = vec2(.5f, .1f*dpi->y);
geo->madness_bar_size.y /= reso->y/2;
geo->madness_bar_pos = vec2(
-1 + geo->padding.x + geo->madness_bar_size.x,
1 - geo->padding.y - geo->madness_bar_size.y);
geo->faith_bar_size = vec2(.4f, .05f*dpi->y);
geo->faith_bar_size.y /= reso->y/2;
geo->faith_bar_pos = vec2(
-1 + geo->padding.x + geo->faith_bar_size.x,
1 - geo->padding.y - geo->madness_bar_size.y*2 - geo->faith_bar_size.y);
geo->effect_bar_size = vec2(3*dpi->x/reso->x, 4/reso->y);
geo->effect_bar_pos = vec2(1-geo->padding.x, -1+geo->padding.y);
vec2_subeq(&geo->effect_bar_pos, &geo->effect_bar_size);
# undef px_to_disp_
}
static glyphas_block_t* loplayer_hud_create_effect_text_block_(
const loplayer_hud_t* hud, const char* text) {
assert(hud != NULL);
glyphas_block_t* block = glyphas_block_new(
GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL,
-hud->geometry.fontsz_normal_px.y,
INT32_MAX,
32);
static const vec4_t white = vec4(1, 1, 1, 1);
glyphas_block_add_characters(
block, hud->font.sans, &white, text, strlen(text));
const vec2_t scale = vec2(
2/hud->shaders->resolution.x, 2/hud->shaders->resolution.y);
glyphas_block_scale(block, &scale);
return block;
}
static void loplayer_hud_initialize_effect_text_(
loplayer_hud_t* hud, loresource_set_t* res) {
assert(hud != NULL);
# define init_effect_text_(name) \
hud->effects.name.text = loplayer_hud_create_effect_text_block_( \
hud, loresource_text_get(res->lang, "effect_"#name))
init_effect_text_(curse);
init_effect_text_(amnesia);
init_effect_text_(lost);
# undef init_effect_
}
static void loplayer_hud_update_bars_(loplayer_hud_t* hud) {
assert(hud != NULL);
const float d = hud->ticker->delta_f;
locommon_easing_smooth_float(
&hud->prev_madness, hud->status->recipient.madness, d*2);
locommon_easing_smooth_float(
&hud->prev_faith, hud->status->recipient.faith, d*2);
}
static void loplayer_hud_update_lasting_effect_(
loplayer_hud_t* hud,
loplayer_hud_effect_t* e,
const loeffect_generic_lasting_param_t* p) {
assert(hud != NULL);
assert(e != NULL);
assert(p != NULL);
const uint64_t end = p->begin + p->duration;
const uint64_t t = hud->ticker->time;
if (p->duration == 0 || end <= t || p->begin > t) {
e->remain = 0;
return;
}
e->remain = 1 - (t - p->begin)*1.f/p->duration;
}
static void loplayer_hud_update_effects_(loplayer_hud_t* hud) {
assert(hud != NULL);
const float d = hud->ticker->delta_f;
loplayer_hud_update_lasting_effect_(
hud, &hud->effects.curse, &hud->status->recipient.effects.curse);
loplayer_hud_update_lasting_effect_(
hud, &hud->effects.amnesia, &hud->status->recipient.effects.amnesia);
hud->effects.lost.remain =
hud->status->recipient.faith > 0? 0: (1-hud->status->recipient.madness);
static const size_t len =
sizeof(hud->effects.array)/sizeof(hud->effects.array[0]);
for (size_t i = 0; i < len; ++i) {
loplayer_hud_effect_t* e = &hud->effects.array[i];
locommon_easing_linear_float(&e->alpha, !!(e->remain > 0), d*2);
}
}
static void loplayer_hud_draw_bars_(const loplayer_hud_t* hud) {
assert(hud != NULL);
const typeof(hud->geometry)* geo = &hud->geometry;
const loshader_hud_bar_drawer_instance_t madness = {
.pos = geo->madness_bar_pos,
.size = geo->madness_bar_size,
.bgcolor = vec4(0, 0, 0, 1*hud->alpha),
.fgcolor = vec4(1, 1, 1, .9f*hud->alpha),
.value = MATH_CLAMP(hud->status->recipient.madness, 0, 1),
.prev_value = MATH_CLAMP(hud->prev_madness, 0, 1),
};
loshader_hud_bar_drawer_add_instance(hud->shaders->drawer.hud_bar, &madness);
const loshader_hud_bar_drawer_instance_t faith = {
.pos = geo->faith_bar_pos,
.size = geo->faith_bar_size,
.bgcolor = vec4(0, 0, 0, 1*hud->alpha),
.fgcolor = vec4(.9f, .9f, .9f, .9f*hud->alpha),
.value = MATH_CLAMP(hud->status->recipient.faith, 0, 1),
.prev_value = MATH_CLAMP(hud->prev_faith, 0, 1),
};
loshader_hud_bar_drawer_add_instance(hud->shaders->drawer.hud_bar, &faith);
}
static void loplayer_hud_draw_effects_(const loplayer_hud_t* hud) {
assert(hud != NULL);
const typeof(hud->geometry)* geo = &hud->geometry;
const float lineheight = hud->geometry.fontsz_normal.y;
float h = 0;
static const size_t len =
sizeof(hud->effects.array)/sizeof(hud->effects.array[0]);
for (size_t i = 0; i < len; ++i) {
const loplayer_hud_effect_t* e = &hud->effects.array[i];
if (e->alpha == 0) continue;
const float y = h*lineheight + geo->effect_bar_pos.y;
static const vec2_t origin = vec2(1, -1);
glyphas_block_set_origin(e->text, &origin);
const vec2_t trans = vec2(1-geo->padding.x, y);
glyphas_block_translate(e->text, &trans);
glyphas_block_set_alpha(e->text, e->alpha);
loshader_hud_text_drawer_add_block(
&hud->shaders->drawer.hud_text, e->text);
const loshader_hud_bar_drawer_instance_t instance = {
.pos = vec2(geo->effect_bar_pos.x, y),
.size = vec2(-geo->effect_bar_size.x, geo->effect_bar_size.y),
.bgcolor = vec4(1, 1, 1, .2f*hud->alpha),
.fgcolor = vec4(1, 1, 1, .8f*hud->alpha),
.value = MATH_CLAMP(e->remain, 0, 1),
.prev_value = MATH_CLAMP(e->remain, 0, 1),
};
loshader_hud_bar_drawer_add_instance(
hud->shaders->drawer.hud_bar, &instance);
h += e->alpha * e->alpha * (3-2*e->alpha);
}
}
loplayer_hud_t* loplayer_hud_new(
loresource_set_t* res,
loshader_set_t* shaders,
const locommon_ticker_t* ticker,
const loplayer_event_t* event,
const loplayer_status_t* status,
const loplayer_entity_t* entity) {
assert(res != NULL);
assert(shaders != NULL);
assert(ticker != NULL);
assert(event != NULL);
assert(status != NULL);
assert(entity != NULL);
loplayer_hud_t* hud = memory_new(sizeof(*hud));
*hud = (typeof(*hud)) {
.shaders = shaders,
.ticker = ticker,
.event = event,
.status = status,
.entity = entity,
};
loplayer_hud_calculate_geometry_(hud);
hud->font = (typeof(hud->font)) {
.sans = glyphas_cache_new(
shaders->tex.hud_text,
&res->font.sans,
hud->geometry.fontsz_normal_px.x,
hud->geometry.fontsz_normal_px.y),
.serif = glyphas_cache_new(
shaders->tex.hud_text,
&res->font.serif,
hud->geometry.fontsz_small_px.x,
hud->geometry.fontsz_small_px.y),
};
hud->biome_text = glyphas_block_new(
GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL,
-hud->geometry.fontsz_normal_px.y,
INT32_MAX,
32);
loplayer_hud_initialize_effect_text_(hud, res);
return hud;
}
void loplayer_hud_delete(loplayer_hud_t* hud) {
if (hud == NULL) return;
static const size_t len =
sizeof(hud->effects.array) / sizeof(hud->effects.array[0]);
for (size_t i = 0; i < len; ++i) {
glyphas_block_delete(hud->effects.array[i].text);
}
glyphas_block_delete(hud->biome_text);
glyphas_cache_delete(hud->font.sans);
glyphas_cache_delete(hud->font.serif);
memory_delete(hud);
}
void loplayer_hud_show(loplayer_hud_t* hud) {
assert(hud != NULL);
hud->shown = true;
}
void loplayer_hud_hide(loplayer_hud_t* hud) {
assert(hud != NULL);
hud->shown = false;
}
void loplayer_hud_set_biome_text(loplayer_hud_t* hud, const char* text) {
assert(hud != NULL);
glyphas_block_clear(hud->biome_text);
static const vec4_t white = vec4(1, 1, 1, 1);
glyphas_block_add_characters(
hud->biome_text, hud->font.serif, &white, text, strlen(text));
glyphas_block_set_origin(hud->biome_text, &vec2(0, -1));
const vec2_t scale = vec2(
2/hud->shaders->resolution.x, 2/hud->shaders->resolution.y);
glyphas_block_scale(hud->biome_text, &scale);
const typeof(hud->geometry)* geo = &hud->geometry;
glyphas_block_translate(
hud->biome_text, &vec2(-1+geo->padding.x, -1+geo->padding.y));
glyphas_block_make_glitched(hud->biome_text, hud->ticker->time);
}
void loplayer_hud_update(loplayer_hud_t* hud) {
assert(hud != NULL);
bool shown = hud->shown;
const loplayer_event_param_t* e = loplayer_event_get_param(hud->event);
if (e != NULL) {
shown = shown && !e->hide_hud;
}
const float dt = hud->ticker->delta_f;
locommon_easing_smooth_float(&hud->alpha, !!shown, dt*2);
loplayer_hud_update_bars_(hud);
loplayer_hud_update_effects_(hud);
}
void loplayer_hud_draw_ui(const loplayer_hud_t* hud) {
assert(hud != NULL);
hud->shaders->drawer.hud_text.alpha = hud->alpha;
loplayer_hud_draw_bars_(hud);
loplayer_hud_draw_effects_(hud);
loshader_hud_text_drawer_add_block(
&hud->shaders->drawer.hud_text, hud->biome_text);
}