/* 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" namespace client { 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); } 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); } 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; } // 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; } float r = ui::pointer_size; if (!is_active_target) r *= 0.5; gl::disable(GL_TEXTURE_2D); // outer square shadow gl::color(0, 0, 0, 1); gl::begin(gl::LineLoop); gl::vertex(cx + r, cy + 2); gl::vertex(cx, cy + r + 2); gl::vertex(cx - r, cy + 2); gl::vertex(cx, cy - r + 2); gl::end(); if (entity->has_flag(core::Entity::Dockable)) { gl::begin(gl::LineLoop); gl::vertex(cx + (r*0.25f), cy + 2); gl::vertex(cx, cy + (r*0.25f) + 2); gl::vertex(cx - (r*0.25f), cy + 2); gl::vertex(cx, cy - (r*0.25f) + 2); 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 faction color } else { gl::color(palette()->foreground()); } // outer square0 gl::begin(gl::LineLoop); gl::vertex(cx + r, cy); gl::vertex(cx, cy + r); gl::vertex(cx - r, cy); gl::vertex(cx, cy - r); gl::end(); if (entity->has_flag(core::Entity::Dockable)) { gl::begin(gl::LineLoop); gl::vertex(cx + (r*0.25f), cy); gl::vertex(cx, cy + (r*0.25f)); gl::vertex(cx - (r*0.25f), cy); gl::vertex(cx, cy - (r*0.25f)); gl::end(); } if (is_active_target) { gl::color(palette()->foreground()); // owner name if (entity->type() == core::Entity::Controlable) { const core::EntityControlable *ec = static_cast(entity); if (ec->health() > 0) { // on-screen health indicator const float f = 2.0f * r * ec->health() / 100.0f; // health bar gl::color(0, 1, 0, 1); gl::begin(gl::Quads); gl::vertex(cx - r, cy + r - 4 - render::Text::fontheight() * 0.5f); gl::vertex(cx - r + f, cy + r - 4 - render::Text::fontheight() * 0.5f); gl::vertex(cx - r + f, cy + r - 4); gl::vertex(cx - r, cy + r - 4); gl::end(); // frame gl::color(palette()->foreground()); gl::begin(gl::LineLoop); gl::vertex(cx - r, cy + r - 4 - render::Text::fontheight() * 0.5f); gl::vertex(cx + r, cy + r - 4 - render::Text::fontheight() * 0.5f); gl::vertex(cx + r, cy + r - 4); gl::vertex(cx - r, cy + r - 4); gl::end(); } gl::enable(GL_TEXTURE_2D); if (ec->owner()) { std::ostringstream strtoplabel; strtoplabel << "^B" << ec->owner()->name() << "^B\n"; render::Text::draw( cx - aux::text_length(strtoplabel.str()) * render::Text::fontwidth() * 0.5f, cy - r - 4 - render::Text::fontheight(), strtoplabel.str() ); } } else { gl::enable(GL_TEXTURE_2D); } gl::color(palette()->foreground()); // on-screen entity name render::Text::draw( cx - aux::text_length(entity->name()) * render::Text::fontwidth() * 0.5f, cy + r + 4, entity->name() ); // on-screen distance std::ostringstream strdistance; 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 << "--"; } render::Text::draw( cx - aux::text_length(strdistance.str()) * render::Text::fontwidth() * 0.5f, cy + r + 4 + render::Text::fontheight(), strdistance.str() ); } } 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(); // 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_target(entity, true); } else if (entity == core::localplayer()->mission_target()) { draw_target(entity, false); } else if ((entity->type() == core::Entity::Controlable) && (targets::is_valid_hud_target(entity))) { draw_target(entity, false); } } gl::disable(GL_TEXTURE_2D); /* // --------------------------------------------------------- // player info pane std::ostringstream playerinfostr; playerinfostr << "^B" << core::localplayer()->name() << '\n'; playerinfostr << "^B" << core::localcontrol()->name() << '\n'; playerinfostr << "^Ncredits: " << core::localplayer()->credits(); Text::draw(width() - 4 - Text::fontwidth() * 52, height() - Text::fontheight() * 3 - 4, playerinfostr.str()); */ /* // --------------------------------------------------------- // target info pane const core::Entity *target = targets::current(); if (target) { std::ostringstream strtarget; if (target->type() == core::Entity::Controlable) { const core::EntityControlable *target_controlable = static_cast(target); if (target_controlable->owner()) { strtarget << "^B" << target_controlable->owner()->name() << "\n"; } else { strtarget << "\n"; } } else { strtarget << "\n"; } strtarget << "^B" << target->name() << "\n^B"; float d = math::distance(core::localcontrol()->location(), target->location()) - target->radius() - core::localcontrol()->radius(); if (d > 0) { strtarget << "^Ndist:^B "; if (d > 100.0f) { strtarget << roundf(d * 0.1f) << "km"; } else { strtarget << roundf(d * 100.0f) << "m"; } if (core::localcontrol()->speed() > 0.1f) { strtarget << "^N eta:^B "; float eta = floorf(d / core::localcontrol()->speed()); if (eta > 60.0f) { float etamin = floorf(eta / 60.0f); strtarget << etamin << "min "; eta -= etamin * 60; } strtarget << eta << "sec"; } } else { strtarget << " --"; } Text::draw(width() - 4 - Text::fontwidth() * 30, height() - Text::fontheight() * 3 - 4, strtarget.str()); } */ /* //---------------------------------------------------------- // engine info pane // draw thruster indicator Textures::bind("bitmaps/hud/thruster_base"); // 316 x 32 bitmap gl::color(1, 1, 1, 1); gl::begin(gl::Quads); glTexCoord2f(0, 0); gl::vertex(4, height() - 4 - 32, 0); glTexCoord2f(1, 0); gl::vertex(4 + 316, height() - 4 - 32, 0); glTexCoord2f(1, 1); gl::vertex(4 + 316, height() - 4 , 0); glTexCoord2f(0, 1); gl::vertex(4, height() - 4 , 0); gl::end(); float u = core::localcontrol()->thrust(); if (core::localcontrol()->state() != core::Entity::Normal) { if ((core::localcontrol()->state() == core::Entity::Docked ) || (core::localcontrol()->state() == core::Entity::NoPower )) { u = 0.0f; } else { u = 1.0f; } } if ((u > 0) || (core::localcontrol()->state() == core::Entity::Impulse)) { if ((core::localcontrol()->state() == core::Entity::Impulse) || (core::localcontrol()->state() == core::Entity::ImpulseInitiate)) { gl::color(0, .8, 0); } else if ((core::localcontrol()->state() == core::Entity::Jump) || (core::localcontrol()->state() == core::Entity::JumpInitiate)) { gl::color(0.8f, 0.0f, 0.0f); } else { float d = math::absf(input::local_thrust - u); if (d > 0.1) { d = 0.1f; } gl::color(1, 1, .5f + d * 5.0f); } Textures::bind("bitmaps/hud/thruster_indicator"); // 316 x 32 bitmap gl::begin(gl::Quads); glTexCoord2f(0, 0); gl::vertex(4, height() - 4 - 32, 0); glTexCoord2f(u, 0); gl::vertex(4.0f + u * 316.0f, height() - 4 - 32, 0); glTexCoord2f(u, 1); gl::vertex(4.0f + u * 316.0f, height() - 4 , 0); glTexCoord2f(0, 1); gl::vertex(4, height() - 4 , 0); gl::end(); } Text::setfont("gui", 14, 24); Text::setcolor('B'); //set normal color std::ostringstream speedstr; speedstr << "^B" << roundf(core::localcontrol()->speed() * 100.0f); Text::draw(316 + 4 + 10, height() - 6 - 16 - render::Text::fontwidth() / 2, speedstr.str()); Text::setfont("gui", 12, 18); Text::setcolor('N'); //set normal color */ 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); } } } }