/* client/hud.cc This file is part of the Osirion project and is distributed under the terms and conditions of the GNU General Public License version 2 */ #include "core/core.h" #include "client/client.h" #include "client/hud.h" #include "client/hudenginestatus.h" #include "client/hudplayerstatus.h" #include "client/hudtargetstatus.h" #include "client/input.h" #include "client/targets.h" #include "render/render.h" #include "render/renderext.h" #include "ui/ui.h" #include "ui/paint.h" namespace client { const float SPLASH_POPUP_DELAY = 0.1f; HUD::HUD(ui::Widget *parent) : Widget(parent) { set_label("hud"); set_border(false); set_background(false); hud_center = new ui::Bitmap(this, "bitmaps/pointers/center"); hud_center->set_color(palette()->pointer()); // player status hud_playerstatus = new HUDPlayerStatus(this); // engine status hud_enginestatus = new HUDEngineStatus(this); // target status hud_targetstatus = new HUDTargetStatus(this); hud_splash_time = 0.0f; hud_last_target = 0; } void HUD::resize() { //hud_toolbar->set_geometry(0.0f, 0.0f, width(), font()->height() *2 ); const float padding = ui::root()->font_large()->height(); hud_center->set_size(ui::pointer_size, ui::pointer_size); hud_center->set_location((size() - hud_center->size()) * 0.5f); const float w = (width() - 4 * padding) / 3.0f; hud_playerstatus->set_size(w,ui::UI::elementsize.height() * 3.0f); hud_playerstatus->set_location(padding, height() - hud_playerstatus->height() - padding); hud_enginestatus->set_size(w,ui::UI::elementsize.height()); hud_enginestatus->set_location(hud_playerstatus->right() + padding, height() - hud_enginestatus->height() - padding); hud_targetstatus->set_size(w,ui::UI::elementsize.height() * 3.0f); hud_targetstatus->set_location(hud_enginestatus->right() + padding, height() - hud_targetstatus->height() - padding); } void HUD::draw_offscreen_target(core::Entity *entity, bool is_active_target) { math::Vector3f target(entity->location() - render::Camera::eye()); target = render::Camera::axis().transpose() * target; float cx = 0; float cy = 0; if (target.y() * target.y() + target.z() * target.z() < 0.0001) { // X - bound, behind (front is visible) cx = 0.0f; cy = -0.5f; } else if (fabs(target.y()) > fabs(target.z())) { // Y-bound cx = math::sgnf(target.y()) * 0.5f; cy = 0.5f * target.z() / fabs(target.y()); } else { // Z-bound cx = 0.5f * target.y() / fabs(target.z()); cy = math::sgnf(target.z()) * 0.5f; } const float r = 16; const float margin = 24; cx = (0.5f - cx) * ((float) render::State::width() - margin * 2); cx += margin; cy = (0.5f - cy) * ((float) render::State::height() - margin * 2); cy += margin; gl::disable(GL_TEXTURE_2D); gl::color(0, 0, 0, 1); gl::begin(gl::LineLoop); glVertex3f(cx + r, cy + 2, 0); glVertex3f(cx, cy + r + 2, 0); glVertex3f(cx - r, cy + 2, 0); glVertex3f(cx, cy - r + 2, 0); gl::end(); if (entity == core::localplayer()->mission_target()) { gl::color(palette()->mission()); } else if (entity->type() == core::Entity::Controlable) { gl::color(0, 1, 0, 1); // FIXME allegiance color } else { gl::color(1, 1, 1, 1); // FIXME neutral color } gl::begin(gl::LineLoop); glVertex3f(cx + r, cy, 0); glVertex3f(cx, cy + r, 0); glVertex3f(cx - r, cy, 0); glVertex3f(cx, cy - r, 0); gl::end(); gl::enable(GL_TEXTURE_2D); } /* * This function is called to draw on-screen targets * if is_active_target is set, the target is the currently selected target * */ void HUD::draw_target(core::Entity *entity, bool is_active_target) { using math::Vector3f; // don't draw target if we're very close to it if (render::ext_render(entity)->distance() < 0.001f) return; // don't draw target if it is outside the visible cone Vector3f target(entity->location() - render::Camera::eye()); if (math::dotproduct(render::Camera::axis().forward(), Vector3f::normalized(target)) < 0.75) { draw_offscreen_target(entity, is_active_target); return; } // calculate target screen position // transform the target into the camera coordinate system target = render::Camera::axis().transpose() * target; // calculate the intersection between the line (0,0,0)-target and the frustum front float t = (render::FRUSTUMFRONT + 0.001f) / target.x(); Vector3f center(target *t); float cx = render::State::width() * (0.5 - center.y()); float cy = render::State::height() * (0.5 - center.z() * render::State::aspect()); if ((cx < 0) || (cy < 0) || (cx > render::State::width()) || (cy > render::State::height())) { draw_offscreen_target(entity, is_active_target); return; } // target bitmap properties float bitmap_radius = 32.0f; if (is_active_target) { bitmap_radius *= 2.0f; if (hud_splash_time > 0.0f) { bitmap_radius *= (core::application()->time() - hud_splash_time) / SPLASH_POPUP_DELAY; } } math::Vector2f bitmap_location(cx - bitmap_radius, cy - bitmap_radius); math::Vector2f bitmap_size(2.0f * bitmap_radius, 2.0f * bitmap_radius); math::Color bitmap_color; std:: string bitmap_material; if (entity->type() == core::Entity::Controlable) { if (is_active_target) { bitmap_material.assign("bitmaps/hud/target_controlable"); } else { bitmap_material.assign("bitmaps/hud/target_default"); } bitmap_color.assign(palette()->fancy()); } else if (entity->has_flag(core::Entity::Dockable)) { bitmap_material.assign("bitmaps/hud/target_dockable"); bitmap_color.assign(palette()->foreground()); } else { bitmap_material.assign("bitmaps/hud/target_default"); bitmap_color.assign(palette()->text()); } if (entity == core::localplayer()->mission_target()) { bitmap_color.assign(palette()->mission()); } ui::Paint::draw_bitmap(bitmap_location, bitmap_size, bitmap_color, bitmap_material); if (!(is_active_target && (hud_splash_time > 0.0f))) { // labels std::string label_text; if (entity->type() == core::Entity::Controlable) { const core::EntityControlable *ec = static_cast(entity); if (ec->owner()) { label_text.append("^B"); label_text.append(ec->owner()->name()); } else { label_text.append("^B"); label_text.append(entity->name()); } } else { if (entity->has_flag(core::Entity::Dockable)) { label_text.append("^B"); } else { label_text.append("^N"); } label_text.append(entity->name()); } const ui::Font *label_font; if (is_active_target) { label_font = ui::root()->font_small(); } else { label_font = ui::root()->font_tiny(); } math::Vector2f label_size(2.0f * bitmap_radius, label_font->height()); math::Vector2f label_location(cx - bitmap_radius, cy + bitmap_radius); ui::Paint::draw_label(label_location, label_size,label_font, label_text); if (is_active_target) { // draw distance std::ostringstream strdistance; if (entity->type() == core::Entity::Controlable) { strdistance << "^B"; } else if (entity->has_flag(core::Entity::Dockable)) { strdistance << "^B"; } else { strdistance << "^N"; } float d = math::distance(core::localcontrol()->location(), entity->location()) - entity->radius() - core::localcontrol()->radius(); if (d > 0) { if (d > 100.0f) { strdistance << roundf(d * 0.1f) << "km"; } else { strdistance << roundf(d * 100.0f) << "m"; } } else { strdistance << "--"; } label_location[1] += - label_size.height(); ui::Paint::draw_label(label_location, label_size, label_font, strdistance.str()); } if (entity->type() == core::Entity::Controlable) { const core::EntityControlable *ec = static_cast(entity); // health bar size const float hb_width = bitmap_radius; float hb_height = ui::root()->font_tiny()->width(); if (!is_active_target) { hb_height *= 0.5f; } const float hb_f = hb_width * ec->health() / 100.0f; math::Vector2f pos; pos[0] = cx - bitmap_radius; pos[0] += bitmap_radius - 0.5f * hb_width; pos[1] = cy - bitmap_radius; // health bar gl::color(0, 1, 0, 1); gl::begin(gl::Quads); gl::vertex(pos[0], pos[1]); gl::vertex(pos[0] + hb_f, pos[1]); gl::vertex(pos[0] + hb_f, pos[1] + hb_height); gl::vertex(pos[0], pos[1] + hb_height); gl::end(); // health bar frame gl::color(palette()->foreground()); gl::begin(gl::LineLoop); gl::vertex(pos[0], pos[1]); gl::vertex(pos[0] + hb_width, pos[1]); gl::vertex(pos[0] + hb_width, pos[1] + hb_height); gl::vertex(pos[0], pos[1] + hb_height); gl::end(); } } } bool HUD::on_keypress(const int key, const unsigned int modifier) { switch (key) { case SDLK_ESCAPE: if (targets::current()) { targets::reset(); } else { Client::show_menu("game"); } return true; } return false; } void HUD::draw() { using namespace render; if (core::localcontrol() && (input::mouse_control || input::joystick_control) && (render::Camera::mode() == render::Camera::Cockpit || render::Camera::mode() == render::Camera::Track)) { hud_center->set_visible(true); } else { hud_center->set_visible(false); } gl::enable(GL_TEXTURE_2D); Text::setfont("gui", 12, 18); Text::setcolor('N'); //set normal color core::Zone *zone = core::localcontrol()->zone(); if (targets::current()) { if (targets::current()->id() != hud_last_target) { hud_splash_time = core::application()->time(); } else if (hud_splash_time + SPLASH_POPUP_DELAY < core::application()->time()) { hud_splash_time = 0.0f; } hud_last_target = targets::current()->id(); } else { hud_splash_time = 0.0f; hud_last_target = 0; } // draw HUD targets for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) { core::Entity *entity = (*it); if (entity == targets::current()) { // draw current HUD target draw_target(entity, true); } else if (entity == core::localplayer()->mission_target()) { // draw current mission target draw_target(entity, false); } else if ((entity->type() == core::Entity::Controlable) && (targets::is_valid_hud_target(entity))) { const core::EntityControlable *ec = static_cast(entity); if (ec->owner()) { // draw other players draw_target(entity, false); } } } gl::disable(GL_TEXTURE_2D); if (has_mouse_focus()) { if (render::Camera::mode() == render::Camera::Overview) { ui::root()->set_pointer("aim"); } else if (targets::hover()) { ui::root()->set_pointer("target", ui::Palette::Active, true); if (input::joystick_lastmoved_time() > input::mouse_lastmoved_time()) { ui::root()->input_mouse(render::State::width() / 2, render::State::height() / 2); } } else if (input::mouse_control) { ui::root()->set_pointer("control", ui::Palette::Pointer); } else if ((input::joystick_lastmoved_time() > input::mouse_lastmoved_time()) && (render::Camera::mode() == render::Camera::Cockpit || render::Camera::mode() == render::Camera::Track)) { ui::root()->set_pointer(); } else { ui::root()->set_pointer("aim", ui::Palette::Foreground); } } } }