ref: 59ebb89ed23d4cebd7d6121cf9961c6bb18bd348
dir: /src/wipeout/hud.c/
#include "../types.h" #include "../mem.h" #include "../utils.h" #include "../system.h" #include "object.h" #include "track.h" #include "ship.h" #include "weapon.h" #include "hud.h" #include "droid.h" #include "camera.h" #include "image.h" #include "ship_ai.h" #include "game.h" #include "ui.h" static texture_list_t weapon_icon_textures; static uint16_t target_reticle; typedef struct { vec2i_t offset; uint16_t height; rgba_t color; } speedo_bar_t; const struct { uint16_t width; uint16_t skew; speedo_bar_t bars[13]; } speedo = { .width = 121, .skew = 2, .bars = { {{.x = 6, .y = 12}, .height = 10, .color = rgba( 66, 16, 49, 255)}, {{.x = 13, .y = 12}, .height = 10, .color = rgba(115, 33, 90, 255)}, {{.x = 20, .y = 12}, .height = 10, .color = rgba(132, 58, 164, 255)}, {{.x = 27, .y = 12}, .height = 10, .color = rgba( 99, 90, 197, 255)}, {{.x = 34, .y = 12}, .height = 10, .color = rgba( 74, 148, 181, 255)}, {{.x = 41, .y = 12}, .height = 10, .color = rgba( 66, 173, 115, 255)}, {{.x = 50, .y = 10}, .height = 12, .color = rgba( 99, 206, 58, 255)}, {{.x = 59, .y = 8}, .height = 12, .color = rgba(189, 206, 41, 255)}, {{.x = 69, .y = 5}, .height = 13, .color = rgba(247, 140, 33, 255)}, {{.x = 81, .y = 2}, .height = 15, .color = rgba(255, 197, 49, 255)}, {{.x = 95, .y = 1}, .height = 16, .color = rgba(255, 222, 115, 255)}, {{.x = 110, .y = 1}, .height = 16, .color = rgba(255, 239, 181, 255)}, {{.x = 126, .y = 1}, .height = 16, .color = rgba(255, 255, 255, 255)} } }; static uint16_t speedo_facia_texture; void hud_load() { speedo_facia_texture = image_get_texture("wipeout/textures/speedo.tim"); target_reticle = image_get_texture_semi_trans("wipeout/textures/target2.tim"); weapon_icon_textures = image_get_compressed_textures("wipeout/common/wicons.cmp"); } static void hud_draw_speedo_bar(vec2i_t *pos, const speedo_bar_t *a, const speedo_bar_t *b, float f, rgba_t color_override) { rgba_t left_color, right_color; if (color_override.as_uint32 > 0) { left_color = color_override; right_color = color_override; } else { left_color = a->color; right_color = rgba( lerp(a->color.as_rgba.r, b->color.as_rgba.r, f), lerp(a->color.as_rgba.g, b->color.as_rgba.g, f), lerp(a->color.as_rgba.b, b->color.as_rgba.b, f), lerp(a->color.as_rgba.a, b->color.as_rgba.a, f) ); } float right_h = lerp(a->height, b->height, f); vec2i_t top_left = vec2i(a->offset.x + 1, a->offset.y); vec2i_t bottom_left = vec2i(a->offset.x + 1 - a->height / speedo.skew, a->offset.y + a->height); vec2i_t top_right = vec2i(lerp(a->offset.x + 1, b->offset.x, f), lerp(a->offset.y, b->offset.y, f)); vec2i_t bottom_right = vec2i(top_right.x - right_h / speedo.skew, top_right.y + right_h); top_left = ui_scaled(top_left); bottom_left = ui_scaled(bottom_left); top_right = ui_scaled(top_right); bottom_right = ui_scaled(bottom_right); render_push_tris((tris_t) { .vertices = { { .pos = {pos->x + bottom_left.x, pos->y + bottom_left.y, 0}, .uv = {0, 0}, .color = left_color }, { .pos = {pos->x + top_right.x, pos->y + top_right.y, 0}, .uv = {0, 0}, .color = right_color }, { .pos = {pos->x + top_left.x, pos->y + top_left.y, 0}, .uv = {0, 0}, .color = left_color }, } }, RENDER_NO_TEXTURE); render_push_tris((tris_t) { .vertices = { { .pos = {pos->x + bottom_right.x, pos->y + bottom_right.y, 0}, .uv = {0, 0}, .color = right_color }, { .pos = {pos->x + top_right.x, pos->y + top_right.y, 0}, .uv = {0, 0}, .color = right_color }, { .pos = {pos->x + bottom_left.x, pos->y + bottom_left.y, 0}, .uv = {0, 0}, .color = left_color }, } }, RENDER_NO_TEXTURE); } static void hud_draw_speedo_bars(vec2i_t *pos, float f, rgba_t color_override) { if (f <= 0) { return; } if (f - floor(f) > 0.9) { f = ceil(f); } if (f > 13) { f = 13; } int bars = f; for (int i = 1; i < bars; i++) { hud_draw_speedo_bar(pos, &speedo.bars[i - 1], &speedo.bars[i], 1, color_override); } if (bars > 12) { return; } float last_bar_fraction = f - bars + 0.1; if (last_bar_fraction <= 0) { return; } if (last_bar_fraction > 1) { last_bar_fraction = 1; } int last_bar = bars == 0 ? 1 : bars; hud_draw_speedo_bar(pos, &speedo.bars[last_bar - 1], &speedo.bars[last_bar], last_bar_fraction, color_override); } static void hud_draw_speedo(int speed, int thrust) { vec2i_t facia_pos = ui_scaled_pos(UI_POS_BOTTOM | UI_POS_RIGHT, vec2i(-141, -45)); vec2i_t bar_pos = ui_scaled_pos(UI_POS_BOTTOM | UI_POS_RIGHT, vec2i(-141, -40)); hud_draw_speedo_bars(&bar_pos, thrust / 65.0, rgba(255, 0, 0, 128)); hud_draw_speedo_bars(&bar_pos, speed / 2166.0, rgba(0, 0, 0, 0)); render_push_2d(facia_pos, ui_scaled(render_texture_size(speedo_facia_texture)), rgba(128, 128, 128, 255), speedo_facia_texture); } static void hud_draw_target_icon(vec3_t position) { vec2i_t screen_size = render_size(); vec2i_t size = ui_scaled(render_texture_size(target_reticle)); vec3_t projected = render_transform(position); vec2i_t pos = vec2i( (( projected.x + 1.0) / 2.0) * screen_size.x - size.x / 2, ((-projected.y + 1.0) / 2.0) * screen_size.y - size.y / 2 ); render_push_2d(pos, size, rgba(128, 128, 128, 128), target_reticle); } void hud_draw(ship_t *ship) { // Current lap time if (ship->lap >= 0) { ui_draw_time(ship->lap_time, ui_scaled_pos(UI_POS_BOTTOM | UI_POS_LEFT, vec2i(16, -30)), UI_SIZE_16, UI_COLOR_DEFAULT); for (int i = 0; i < ship->lap && i < NUM_LAPS-1; i++) { ui_draw_time(g.lap_times[ship->pilot][i], ui_scaled_pos(UI_POS_BOTTOM | UI_POS_LEFT, vec2i(16, -45 - (10 * i))), UI_SIZE_8, UI_COLOR_ACCENT); } } // Current Lap int display_lap = max(0, ship->lap + 1); ui_draw_text("LAP", ui_scaled(vec2i(15, 8)), UI_SIZE_8, UI_COLOR_ACCENT); ui_draw_number(display_lap, ui_scaled(vec2i(10, 19)), UI_SIZE_16, UI_COLOR_DEFAULT); int width = ui_char_width('0' + display_lap, UI_SIZE_16); ui_draw_text("OF", ui_scaled(vec2i((10 + width), 27)), UI_SIZE_8, UI_COLOR_ACCENT); ui_draw_number(NUM_LAPS, ui_scaled(vec2i((32 + width), 19)), UI_SIZE_16, UI_COLOR_DEFAULT); // Race Position if (g.race_type != RACE_TYPE_TIME_TRIAL) { ui_draw_text("POSITION", ui_scaled_pos(UI_POS_TOP | UI_POS_RIGHT, vec2i(-90, 8)), UI_SIZE_8, UI_COLOR_ACCENT); ui_draw_number(ship->position_rank, ui_scaled_pos(UI_POS_TOP | UI_POS_RIGHT, vec2i(-60, 19)), UI_SIZE_16, UI_COLOR_DEFAULT); } // Framerate if (save.show_fps) { ui_draw_text("FPS", ui_scaled(vec2i(16, 78)), UI_SIZE_8, UI_COLOR_ACCENT); ui_draw_number((int)(g.frame_rate), ui_scaled(vec2i(16, 90)), UI_SIZE_8, UI_COLOR_DEFAULT); } // Lap Record ui_draw_text("LAP RECORD", ui_scaled(vec2i(15, 43)), UI_SIZE_8, UI_COLOR_ACCENT); ui_draw_time(save.highscores[g.race_class][g.circut][g.highscore_tab].lap_record, ui_scaled(vec2i(15, 55)), UI_SIZE_8, UI_COLOR_DEFAULT); // Wrong way if (flags_not(ship->flags, SHIP_DIRECTION_FORWARD)) { ui_draw_text_centered("WRONG WAY", ui_scaled_pos(UI_POS_MIDDLE | UI_POS_CENTER, vec2i(-20, 0)), UI_SIZE_16, UI_COLOR_ACCENT); } // Speedo int speedo_speed = (g.camera.update_func == camera_update_attract_internal) ? ship->speed * 7 : ship->speed; hud_draw_speedo(speedo_speed, ship->thrust_mag); // Weapon icon if (ship->weapon_type != WEAPON_TYPE_NONE) { vec2i_t pos = ui_scaled_pos(UI_POS_TOP | UI_POS_CENTER, vec2i(-16, 20)); vec2i_t size = ui_scaled(vec2i(32, 32)); uint16_t icon = texture_from_list(weapon_icon_textures, ship->weapon_type-1); render_push_2d(pos, size, rgba(128,128,128,255), icon); } // Lives if (g.race_type == RACE_TYPE_CHAMPIONSHIP) { for (int i = 0; i < g.lives; i++) { ui_draw_icon(UI_ICON_STAR, ui_scaled_pos(UI_POS_BOTTOM | UI_POS_RIGHT, vec2i(-26 - 13 * i, -50)), UI_COLOR_DEFAULT); } } // Weapon target reticle if (ship->weapon_target) { hud_draw_target_icon(ship->weapon_target->position); } }