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); }; };