/* 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/hud.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_toolbar = new ui::Toolbar(this); hud_toolbar->add_button("", "Menu", "ui_menu"); hud_toolbar->add_button("", "Chat", "ui_chat"); hud_toolbar->add_button("", "Map", "ui_map"); */ hud_center = new ui::Bitmap(this, "bitmaps/pointers/center"); hud_center->set_color(palette()->pointer()); } void HUD::resize() { //hud_toolbar->set_geometry(0.0f, 0.0f, width(), font()->height() *2 ); hud_center->set_size(ui::pointer_size, ui::pointer_size); hud_center->set_location((size() - hud_center->size()) * 0.5f); } 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->flags() & core::Entity::Dockable) == 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 allegiance color } else { gl::color(1, 1, 1, 1); // FIXME neutral color } // 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->flags() & core::Entity::Dockable) == 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(); } gl::enable(GL_TEXTURE_2D); if (is_active_target) { // entity name and 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 << "--"; } // owner name if (entity->type() == core::Entity::Controlable) { const core::EntityControlable *ec = static_cast(entity); if (ec->owner()) { render::Text::setcolor('B'); render::Text::draw(cx - aux::text_length(ec->owner()->name()) * render::Text::fontwidth()*0.5f, cy - r - 4 - 2*render::Text::fontheight(), ec->owner()->name()); } render::Text::setcolor('B'); } else if (entity == core::localplayer()->mission_target()) { gl::color(palette()->mission()); } else { render::Text::setcolor('N'); } render::Text::draw(cx - aux::text_length(entity->name()) * render::Text::fontwidth()*0.5f, cy - r - 4 - render::Text::fontheight(), entity->name()); render::Text::draw(cx - aux::text_length(strdistance.str()) * render::Text::fontwidth() * 0.5f, cy + r + 4, strdistance.str()); } } bool HUD::on_keypress(const int key, const unsigned int modifier) { switch (key) { case SDLK_ESCAPE: if (targets::current()) { targets::reset(); } else { ui::root()->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); } } /* unsigned int state = core::localcontrol()->state(); if (state) { std::ostringstream statestr; statestr.clear(); if (state == core::Entity::ImpulseInitiate) { statestr << "^FInitializing kinetic impulse drive " << core::localcontrol()->timer(); } else if (state == core::Entity::Impulse) { //statestr << "^FKinetic impulse"; } else if (state == core::Entity::JumpInitiate) { statestr << "^FInitializing hyperspace jump drive " << core::localcontrol()->timer(); } else if (state == core::Entity::Jump) { statestr << "^FJumping..."; } Text::draw(4, render::State::height() - Text::fontheight()*3 - 4, statestr.str()); } */ const core::Entity *target = targets::current(); if (target) { std::ostringstream strtarget; 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()*2 - 4, strtarget.str()); } // draw player info std::ostringstream playerinfostr; playerinfostr << "^B" << core::localcontrol()->name() << '\n' << "^Ncredits: " << core::localplayer()->credits(); Text::draw(width() - 4 - Text::fontwidth()*52, height() - Text::fontheight()*2 - 4, playerinfostr.str()); // 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 gl::disable(GL_TEXTURE_2D); } }