From ae44478b30d890fe0fb04022f44d474dcdcc3f9d Mon Sep 17 00:00:00 2001 From: Lassi Pulkkinen Date: Thu, 31 Oct 2024 03:11:21 +0200 Subject: Initial commit (import old repo) --- hud.ha | 258 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 hud.ha (limited to 'hud.ha') diff --git a/hud.ha b/hud.ha new file mode 100644 index 0000000..d39dc3d --- /dev/null +++ b/hud.ha @@ -0,0 +1,258 @@ +use gl::*; +use glm; +use math; +use strconv; +use strings; +use trace; +use types; + +let TEXTURE_GUI_ICONS = 0u; + +def HUD_WIDTH = 182.0f32; +def HUD_HEALTH_YOFFSET = 39.0f32; + +fn hud_load() void = { + TEXTURE_GUI_ICONS = texture_upload( + textures_find("minecraft:gui/icons") as *Texture, + &trace::root); +}; + +const LAYER_HUD = Layer { + blocks_input = &layer_hud_blocks_input, + input = &layer_hud_input, + is_opaque = &layer_hud_is_opaque, + render = &layer_hud_render, +}; + +fn layer_hud_blocks_input() bool = { + return false; +}; + +fn layer_hud_input(event: InputEvent) bool = { + return false; +}; + +fn layer_hud_is_opaque() bool = { + return false; +}; + +fn layer_hud_render() void = { + if (CLIENT_STATE != ClientState::GAME) { + return; + }; + + let (width, height) = drawable_size(); + let gui_width = width / gui_scale(); + let gui_height = height / gui_scale(); + + const trans = gui_proj(); + + // crosshair + + if (GAMEMODE != Gamemode::SPECTATOR) { + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR); + + render_rect_textured(trans, + ((gui_width - 15) / 2): f32, ((gui_height - 15) / 2): f32, + 15.0, 15.0, + [255...], + 0.0, 0.0, 15.0, 15.0, + TEXTURE_GUI_ICONS, 256, 256); + }; + + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + const left = gui_width: f32 * 0.5 - HUD_WIDTH * 0.5; + const right = gui_width: f32 * 0.5 + HUD_WIDTH * 0.5; + + const survival = GAMEMODE == Gamemode::SURVIVAL + || GAMEMODE == Gamemode::ADVENTURE; + + // xp bar + + if (survival) { + const progress = 0.0f32; // TODO + const progress = math::ceilf64(progress * HUD_WIDTH): f32; + const y = gui_height: f32 - 29.0; + const height = 5.0f32; + render_rect_textured(trans, left, y, HUD_WIDTH, height, + [255...], + 0.0, 64.0, HUD_WIDTH, height, + TEXTURE_GUI_ICONS, 256, 256); + + render_rect_textured(trans, left, y, progress, height, + [255...], + 0.0, 69.0, progress, height, + TEXTURE_GUI_ICONS, 256, 256); + + const level = 0u32; // TODO + if (level != 0) { + // XXX: let's not take risks here with the static + // alloc... + const text = strings::dup(strconv::u32tos(level)); + defer free(text); + const font = fonts_find("minecraft:default") as *Font; + const metrics = font_measure(font, text); + // TODO: harec weirdness... + let x = (gui_width: f32 - metrics.width) * 0.5; + const y = gui_height: f32 - 35.0; + // TODO: this is how minecraft does it; however it looks + // ugly with high-res fonts (unifont included!). should + // probably take font resolution into account, or use a + // shader thing or something. + const text_trans = glm::translation_make(&[x - 1.0, y, 0.0]); + const text_trans = glm::m4_mul(trans, &text_trans); + render_text(text, font, &text_trans, [0...]); + const text_trans = glm::translation_make(&[x + 1.0, y, 0.0]); + const text_trans = glm::m4_mul(trans, &text_trans); + render_text(text, font, &text_trans, [0...]); + const text_trans = glm::translation_make(&[x, y - 1.0, 0.0]); + const text_trans = glm::m4_mul(trans, &text_trans); + render_text(text, font, &text_trans, [0...]); + const text_trans = glm::translation_make(&[x, y + 1.0, 0.0]); + const text_trans = glm::m4_mul(trans, &text_trans); + render_text(text, font, &text_trans, [0...]); + const text_trans = glm::translation_make(&[x, y, 0.0]); + const text_trans = glm::m4_mul(trans, &text_trans); + render_text(text, font, &text_trans, [128, 255, 32, 255]); + }; + }; + + // icon bars left + + const x = left; + let y = gui_height: f32 - HUD_HEALTH_YOFFSET; + + if (survival) { + // XXX: absorption really screwed over any attempt at simplicity + // here... + + const health = math::ceilf64(PLAYER_HEALTH): f32; + const health = if (health > 0.0) health else 0.0f32; + const health = health: u32; + const max_health = 20u32; // TODO + const max_health = if (health > max_health) + health else max_health; + const nhearts = (max_health >> 1) + (max_health & 1); + const nhealth_rows = (nhearts + 9) / 10; + + const extra_health = math::ceilf64(0.0f32): f32; // TODO + const extra_health = extra_health: u32; + const nextra_hearts = (extra_health >> 1) + (extra_health & 1); + const nextra_health_rows = (nextra_hearts + 9) / 10; + + const nrows = nhealth_rows + nextra_health_rows; + const row_height = if (nrows <= 9) 12 - nrows else 3u32; + const row_height = row_height: f32; + + hud_render_icon_bar(trans, + extra_health, 0, + x, y - nhealth_rows: f32 * row_height, 8.0, -row_height, + 16.0, 0.0, 160.0, 0.0, 169.0, 0.0); + hud_render_icon_bar(trans, + health, max_health, + x, y, 8.0, -row_height, + 16.0, 0.0, 52.0, 0.0, 61.0, 0.0); + y -= 10.0 + (nrows - 1): f32 * row_height; + }; + + const armor = 0u32; // TODO + const max_armor = 20u32; // TODO + if (survival && armor != 0) { + y -= hud_render_simple_icon_bar(trans, + armor, max_armor, x, y, 8.0, + 16.0, 9.0, 34.0, 9.0, 25.0, 9.0); + }; + + // icon bars right + + const x = right - 9.0; + let y = gui_height: f32 - HUD_HEALTH_YOFFSET; + + if (false) { // TODO + const vehicle_health = 20u32; // TODO + const max_vehicle_health = 20u32; // TODO + y -= hud_render_simple_icon_bar(trans, + vehicle_health, max_vehicle_health, x, y, -8.0, + 52.0, 9.0, 88.0, 9.0, 97.0, 9.0); + }; + + if (survival) { + const food = PLAYER_FOOD: u32; + const max_food = 20u32; // TODO + y -= hud_render_simple_icon_bar(trans, + food, max_food, x, y, -8.0, + 16.0, 27.0, 52.0, 27.0, 61.0, 27.0); + }; + + const air = 300u32; // TODO + const max_air = 300u32; // TODO + if (survival && air != max_air) { // TODO: always show when underwater + const air_rem = (air * 10 + max_air - 1) % max_air; + const air_bubbles = (air * 10 + max_air - 1) / max_air; + const air_bubbles = if (air_rem < 20) + air_bubbles * 2 - 1 else air_bubbles * 2; + y -= hud_render_simple_icon_bar(trans, + air_bubbles, 20, x, y, -8.0, + 70.0, 18.0, 16.0, 18.0, 25.0, 18.0); + }; +}; + +fn hud_render_simple_icon_bar( + trans: *glm::m4, + amount: u32, max: u32, + x: f32, y: f32, xstep: f32, + ubg: f32, vbg: f32, + ufull: f32, vfull: f32, + uhalf: f32, vhalf: f32, +) f32 = { + const max = if (amount > max) amount else max; + const nicons = (max >> 1) + (max & 1); + const nrows = (nicons + 9) / 10; + const row_height = if (nrows <= 9) 12 - nrows else 3u32; + const row_height = row_height: f32; + hud_render_icon_bar(trans, amount, max, + x, y, xstep, -row_height, + ubg, vbg, ufull, vfull, uhalf, vhalf); + return 10.0 + row_height * (nrows - 1): f32; +}; + +fn hud_render_icon_bar( + trans: *glm::m4, + amount: u32, max: u32, + x: f32, y: f32, xstep: f32, ystep: f32, + ubg: f32, vbg: f32, + ufull: f32, vfull: f32, + uhalf: f32, vhalf: f32, +) void = { + const max = if (amount > max) amount else max; + const nicons = (max >> 1) + (max & 1); + + for (let i = nicons; i > 0) { + i -= 1; + + const x_ = x + (i % 10): f32 * xstep; + const y_ = y + (i / 10): f32 * ystep; + + render_rect_textured(trans, x_, y_, 9.0, 9.0, + [255...], + ubg, vbg, 9.0, 9.0, + TEXTURE_GUI_ICONS, 256, 256); + + if (i * 2 >= amount) { + continue; + }; + + let (ufg, vfg) = if (i * 2 + 1 == amount) + (uhalf, vhalf) else (ufull, vfull); + + render_rect_textured(trans, x_, y_, 9.0, 9.0, + [255...], + ufg, vfg, 9.0, 9.0, + TEXTURE_GUI_ICONS, 256, 256); + }; +}; -- cgit v1.2.3