From 272d229094309bc5875287a5063f818c58c5f4f8 Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Sat, 10 Jan 2009 15:36:15 +0000 Subject: hud widget, drawing code reorganization --- src/client/Makefile.am | 10 +- src/client/client.cc | 31 ++- src/client/client.h | 1 + src/client/hud.cc | 371 +++++++++++++++++++++++++++++++++ src/client/hud.h | 48 +++++ src/client/input.cc | 2 +- src/client/video.cc | 128 +++++++++++- src/client/video.h | 11 + src/client/view.cc | 548 ++----------------------------------------------- src/client/view.h | 26 +-- 10 files changed, 599 insertions(+), 577 deletions(-) create mode 100644 src/client/hud.cc create mode 100644 src/client/hud.h diff --git a/src/client/Makefile.am b/src/client/Makefile.am index 4f78bbe..ad011d0 100644 --- a/src/client/Makefile.am +++ b/src/client/Makefile.am @@ -7,13 +7,13 @@ else noinst_LTLIBRARIES = libclient.la endif -libclient_la_SOURCES = action.cc chat.cc client.cc clientext.cc input.cc \ - joystick.cc key.cc keyboard.cc map.cc notifications.cc soundext.cc targets.cc \ - video.cc view.cc +libclient_la_SOURCES = action.cc chat.cc client.cc clientext.cc hud.cc \ + input.cc joystick.cc key.cc keyboard.cc map.cc notifications.cc soundext.cc targets.cc video.cc view.cc libclient_la_CFLAGS = $(LIBSDL_CFLAGS) $(GL_CFLAGS) libclient_la_LDFLAGS = -avoid-version -no-undefined $(GL_LIBS) $(LIBSDL_LIBS) -noinst_HEADERS = action.h chat.h client.h clientext.h input.h joystick.h key.h \ - keyboard.h map.h notifications.h soundext.h targets.h video.h view.h +noinst_HEADERS = action.h chat.h client.h clientext.h hud.h input.h joystick.h \ + key.h keyboard.h map.h notifications.h soundext.h targets.h video.h \ + view.h libclient_la_LIBADD = $(top_builddir)/src/core/libcore.la $(top_builddir)/src/audio/libaudio.la \ $(top_builddir)/src/render/librender.la $(top_builddir)/src/ui/libui.la diff --git a/src/client/client.cc b/src/client/client.cc index bb6fb55..b897480 100644 --- a/src/client/client.cc +++ b/src/client/client.cc @@ -110,7 +110,10 @@ void Client::init(int count, char **arguments) func = core::Func::add("r_restart", Client::func_r_restart); func->set_info("restart render subsystem"); - + + func = core::Func::add("snd_restart", Client::func_snd_restart); + func->set_info("restart audio subsystem"); + func = core::Func::add("ui_chat", Client::func_ui_chat); func->set_info("toggle chat window"); @@ -120,8 +123,8 @@ void Client::init(int count, char **arguments) func = core::Func::add("ui_map", Client::func_ui_map); func->set_info("toggle map"); - func = core::Func::add("snd_restart", Client::func_snd_restart); - func->set_info("restart audio subsystem"); + func = core::Func::add("ui_menu", Client::func_ui_menu); + func->set_info("toggle main menu"); previous_timestamp = 0; } @@ -228,9 +231,11 @@ void Client::shutdown() if (connected()) disconnect(); core::Func::remove("r_restart"); + core::Func::remove("snd_restart"); core::Func::remove("ui_chat"); core::Func::remove("ui_chatsmall"); - core::Func::remove("snd_restart"); + core::Func::remove("ui_map"); + core::Func::remove("ui_menu"); audio::shutdown(); @@ -374,5 +379,23 @@ void Client::func_ui_map(std::string const &args) } } +void Client::func_ui_menu(std::string const &args) +{ + if (client()->connected()) { + if (ui::root()->active()) { + ui::root()->hide_menu(); + } else { + // show the main menu on non-interactive modules + if (!core::game()->interactive()) { + ui::root()->show_menu("main"); + } else { + ui::root()->show_menu("game"); + } + } + } else { + con_print << "Not connected." << std::endl; + } +} + } // namespace client diff --git a/src/client/client.h b/src/client/client.h index 607c7f0..e98eaf4 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -72,6 +72,7 @@ private: static void func_ui_chat(std::string const &args); static void func_ui_chatsmall(std::string const &args); static void func_ui_map(std::string const &args); + static void func_ui_menu(std::string const &args); View *client_view; diff --git a/src/client/hud.cc b/src/client/hud.cc new file mode 100644 index 0000000..1eb2591 --- /dev/null +++ b/src/client/hud.cc @@ -0,0 +1,371 @@ +/* + 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" + +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, "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::Camera::frustum_front() + 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::stringstream 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 << "--"; + } + if (entity->type() == core::Entity::Controlable) { + render::Text::setcolor('B'); + } 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); + } +} + +void HUD::draw() +{ + using namespace render; + std::stringstream status; + + 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 + + // draw a basic HUD + if(core::localplayer()->view()) { + Text::setcolor('N'); //set normal color + Text::draw(render::State::width()-4-Text::fontwidth()*32, render::State::height()-Text::fontheight()*3-4, core::localcontrol()->zone()->name()); + + Text::setcolor('B'); //set bold color + Text::draw(render::State::width() - 4-Text::fontwidth()*32, render::State::height() - Text::fontheight()*2 -4, core::localplayer()->view()->name()); + + } else if (core::localcontrol() && core::localcontrol()->zone()) { + core::Zone *zone = core::localcontrol()->zone(); + + // draw targets + for (core::Zone::Content::iterator it=zone->content().begin(); it != zone->content().end(); it++) { + core::Entity *entity = (*it); + + if (targets::is_legal_target(entity)) { + if (entity == core::localplayer()->mission_target()) { + draw_target(entity, true); + } else if (entity == targets::current()) { + draw_target(entity, true); + } else if (entity->type() == core::Entity::Controlable) { + draw_target(entity, false); + } + } + } + + unsigned int state = core::localcontrol()->eventstate(); + if (state) { + std::stringstream 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); + } + + core::Entity *target = targets::current(); + std::stringstream strdistance; + float d = 0; + float y = 1.0f; + + if (target) { + std::stringstream strtarget; + strtarget << "^B" << target->name() << "\n^B"; + + 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 << " --"; + } + strtarget << '\n'; + Text::draw(render::State::width() - 4-Text::fontwidth()*32, render::State::height() - Text::fontheight()*2 -4, strtarget); + y += 2.0f; + } + + Text::setcolor('N'); //set normal color + Text::draw(render::State::width()-4-Text::fontwidth()*32, render::State::height()-Text::fontheight()*y-4, core::localcontrol()->zone()->name()); + + 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, render::State::height() - 4 - 32, 0); + + glTexCoord2f(1, 0); + gl::vertex(4 + 316, render::State::height() - 4 - 32, 0); + + glTexCoord2f(1, 1); + gl::vertex(4 + 316, render::State::height() - 4 , 0); + + glTexCoord2f(0, 1); + gl::vertex(4, render::State::height() - 4 , 0); + + gl::end(); + + float u = core::localcontrol()->thrust(); + if (core::localcontrol()->eventstate() == core::Entity::Impulse) { + u = 1.0; + } + + if (( u > 0) || (core::localcontrol()->eventstate() == core::Entity::Impulse)) { + + if (core::localcontrol()->eventstate() == core::Entity::Impulse) { + gl::color(0, .8, 0); + } 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, render::State::height() - 4 - 32, 0); + + glTexCoord2f(u, 0); + gl::vertex(4.0f + u * 316.0f, render::State::height() - 4 - 32, 0); + + glTexCoord2f(u, 1); + gl::vertex(4.0f + u * 316.0f, render::State::height() - 4 , 0); + + glTexCoord2f(0, 1); + gl::vertex(4, render::State::height() - 4 , 0); + + gl::end(); + } + + Text::setfont("gui", 14, 24); + Text::setcolor('B'); //set normal color + + std::stringstream speedstr; + speedstr << "^B" << roundf(core::localcontrol()->speed() * 100.0f); + Text::draw( 316+4+10, render::State::height() - 6 -16 - render::Text::fontwidth() /2, speedstr); + + Text::setfont("gui", 12, 18); + Text::setcolor('N'); //set normal color + } + + gl::disable(GL_TEXTURE_2D); +} + +} diff --git a/src/client/hud.h b/src/client/hud.h new file mode 100644 index 0000000..6882239 --- /dev/null +++ b/src/client/hud.h @@ -0,0 +1,48 @@ +/* + client/hud.h + This file is part of the Osirion project and is distributed under + the terms and conditions of the GNU General Public License version 2 +*/ + +#ifndef __INCLUDED_CLIENT_HUD_H__ +#define __INCLUDED_CLIENT_HUD_H__ + +#include "ui/bitmap.h" +#include "ui/toolbar.h" +#include "ui/widget.h" + +namespace client +{ + +/// widget that contains HUD elements +/** + * The contains all user interface elements + * that are only visible if the client is connected + * and the core is running an interactive module + **/ +class HUD : public ui::Widget { +public: + /// create a new HUD widget + HUD(ui::Widget *parent=0); + +protected: + /// draw hud elements + virtual void draw(); + + /// rearrange child widgets + virtual void resize(); + +private: + + void draw_offscreen_target(core::Entity *entity, bool is_active_target); + + void draw_target(core::Entity *entity, bool is_active_target); + + ui::Bitmap *hud_center; + ui::Toolbar *hud_toolbar; +}; + +} + +#endif // __INCLUDED_CLIENT_HUD_H__ + diff --git a/src/client/input.cc b/src/client/input.cc index a5af430..9293404 100644 --- a/src/client/input.cc +++ b/src/client/input.cc @@ -782,7 +782,7 @@ void frame() for (Keyboard::iterator it = keyboard->begin(); it != keyboard->end(); it++) { key = (*it).second; - if (key && key->pressed()) { + if (key && (key->sym() < 512) && key->pressed()) { if ((key->pressed()+delay < core::application()->time()) && (key->lastpressed()+repeat < core::application()->time())) { key->key_lastpressed = core::application()->time(); key_pressed(key); diff --git a/src/client/video.cc b/src/client/video.cc index 1db1ba4..57efa96 100644 --- a/src/client/video.cc +++ b/src/client/video.cc @@ -8,6 +8,7 @@ #include "client/input.h" #include "client/view.h" #include "client/client.h" +#include "client/targets.h" #include "render/render.h" #include "core/core.h" #include "core/gameserver.h" @@ -21,6 +22,18 @@ using namespace render; namespace client { +/* -- engine variables --------------------------------------------- */ + +core::Cvar *r_width = 0; +core::Cvar *r_height = 0; +core::Cvar *r_fullscreen = 0; + +core::Cvar *draw_ui = 0; +core::Cvar *draw_stats = 0; +core::Cvar *draw_devinfo = 0; +core::Cvar *draw_keypress = 0; + + namespace video { float fullscreen = 0; @@ -37,17 +50,11 @@ int height_prev = 0; const int width_default = 1024; const int height_default = 768; -/* -- engine variables --------------------------------------------- */ - -core::Cvar *r_width; -core::Cvar *r_height; -core::Cvar *r_fullscreen; - bool init() { con_print << "^BInitializing video..." << std::endl; - // initialize cvars + // initialize engine variables r_width = core::Cvar::get("r_width", width_default, core::Cvar::Archive); r_width->set_info("[int] video resolution width"); @@ -57,6 +64,18 @@ bool init() r_fullscreen = core::Cvar::get("r_fullscreen", "0", core::Cvar::Archive); r_fullscreen->set_info("[bool] enable or disable fullscreen video"); + draw_devinfo = core::Cvar::get("draw_devinfo", "0", core::Cvar::Archive); + draw_devinfo->set_info("[bool] draw developer information"); + + draw_stats = core::Cvar::get("draw_stats", "0", core::Cvar::Archive); + draw_stats->set_info("[bool] draw network and render statistics"); + + draw_keypress = core::Cvar::get("draw_keypress", "0", core::Cvar::Archive); + draw_keypress->set_info("[bool] draw keypress key names"); + + draw_ui = core::Cvar::get("draw_ui", "1", core::Cvar::Archive); + draw_ui->set_info("[bool] draw the user interface"); + if( SDL_InitSubSystem(SDL_INIT_VIDEO) < 0 ) { con_error << "SDL_InitSubSystem() failed: " << SDL_GetError() << std::endl; return false; @@ -160,7 +179,8 @@ bool init() // apply render options ui::root()->apply_render_options(); - view::init(); + // initialize target drawer + targets::init(); return true; } @@ -204,14 +224,100 @@ void restart() input::reset(); } +void set_cursor() +{ + if (ui::console()->visible()) { + ui::root()->set_pointer(); + + } else if(core::localplayer()->view() || ui::root()->active()) { + + ui::root()->set_pointer("pointer"); + + } else if (!core::localcontrol()) { + + ui::root()->set_pointer(); + + } else if (client()->view()->map()->hover()) { + + ui::root()->set_pointer("pointer"); + + } else 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); + + if (input::mouse_deadzone) { + ui::root()->input_mouse(render::State::width()/2, render::State::height() /2); + } + + } 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); + } +} + void frame(float elapsed) { // detect fullscreen/windowed mode switch if (fullscreen != r_fullscreen->value()) restart(); - // render a client frame - view::frame(elapsed); + using namespace render; + + // Clear the color and depth buffers. + gl::clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + render::Stats::clear(); + + if (core::application()->connected() && core::game()->time() && core::localplayer()->zone()) { + render::Camera::frame(elapsed); + render::Camera::frustum(); + + render::draw(elapsed); // draw the world + targets::frame(); // validate current target, render sound + + if (!core::localplayer()->view() && targets::current()) // draw target docks etc + render::draw_target(targets::current()); + + render::Camera::ortho(); + + } else { + render::Camera::ortho(); + } + + gl::color(1.0f, 1.0f, 1.0f, 1.0f); + gl::disable(GL_TEXTURE_2D); + gl::enable(GL_BLEND); + + // draw the user interface + if (draw_ui->value()) { + + set_cursor(); + ui::root()->frame(); + + } else if (ui::console()->visible()) { + + ui::console()->event_draw(); + } + + gl::disable(GL_TEXTURE_2D); + gl::disable(GL_BLEND); SDL_GL_SwapBuffers(); } @@ -220,7 +326,7 @@ void shutdown() { con_print << "^BShutting down video..." << std::endl; - view::shutdown(); + targets::shutdown(); render::shutdown(); diff --git a/src/client/video.h b/src/client/video.h index 833ebc4..d085f03 100644 --- a/src/client/video.h +++ b/src/client/video.h @@ -7,6 +7,8 @@ #ifndef __INCLUDED_CLIENT_VIDEO_H__ #define __INCLUDED_CLIENT_VIDEO_H__ +#include "core/cvar.h" + namespace client { /// the video subsystem @@ -35,6 +37,15 @@ namespace video } // namespace video +extern core::Cvar *r_width; +extern core::Cvar *r_height; +extern core::Cvar *r_fullscreen; + +extern core::Cvar *draw_ui; +extern core::Cvar *draw_stats; +extern core::Cvar *draw_devinfo; +extern core::Cvar *draw_keypress; + } // namespace client #endif // __INCLUDED_CLIENT_VIDEO_H__ diff --git a/src/client/view.cc b/src/client/view.cc index 1c1b108..d8346cb 100644 --- a/src/client/view.cc +++ b/src/client/view.cc @@ -29,13 +29,6 @@ namespace client { -core::Cvar *draw_ui = 0; -core::Cvar *draw_stats = 0; -core::Cvar *draw_devinfo = 0; -core::Cvar *draw_keypress = 0; - -unsigned long previousframe = 0; - void time_to_stream(std::stringstream &str, float time) { int minutes = (int) floorf(time / 60.0f); @@ -193,24 +186,14 @@ View::View(ui::Widget *parent) : ui::Widget(parent) set_label("view"); set_border(false); - // initialize client variables - draw_devinfo = core::Cvar::get("draw_devinfo", "0", core::Cvar::Archive); - draw_devinfo->set_info("[bool] draw developer information"); - - draw_stats = core::Cvar::get("draw_stats", "0", core::Cvar::Archive); - draw_stats->set_info("[bool] draw network and render statistics"); - - draw_keypress = core::Cvar::get("draw_keypress", "0", core::Cvar::Archive); - draw_keypress->set_info("[bool] draw keypress key names"); - // add child widgets - view_center = new ui::Bitmap(this, "pointers/center"); view_devinfo = new DevInfo(this); view_stats = new Stats(this); view_keypress = new KeyPress(this); view_notify = new Notifications(this); view_chat = new Chat(this); view_map = new Map(this); + view_hud = new HUD(this); // make sure the view is at the bottom of the draw stack lower(); @@ -220,6 +203,10 @@ void View::resize() { set_size(parent()->size()); + // set hud geometry + view_hud->set_geometry(0,0, width(), height()); + view_hud->event_resize(); + // reposition devinfo widget view_devinfo->set_size(font()->width()*32, font()->height()*5); view_devinfo->set_location(font()->width() * 0.5f, font()->height() * 0.5f); @@ -237,11 +224,6 @@ void View::resize() view_map->set_size(width() - font()->width() * 8, height() - font()->height() * 8); view_map->set_location(font()->width() * 4, font()->height() * 4); - // reposition center - view_center->set_size(ui::pointer_size, ui::pointer_size); - view_center->set_location((size() - view_center->size()) * 0.5f); - view_center->set_color(palette()->pointer()); - // reposition notifications view_notify->set_location(ui::UI::elementsize.width()*2.0f+ font()->width(), view_devinfo->top() + view_devinfo->height() + font()->height()); view_notify->set_size(width() - ui::UI::elementsize.width()*2.0f - font()->width() * 2, height() * 0.5f - view_notify->top()); @@ -249,6 +231,13 @@ void View::resize() void View::draw() { + // draw hud only when connected and controlling a spacecraft + if (core::application()->connected() && core::localcontrol() && !ui::root()->active()) { + view_hud->set_visible(true); + } else { + view_hud->set_visible(false); + } + // reposition chat widget if (!view_chat->small_view()) { view_chat->set_location(font()->width(), view_devinfo->top() + view_devinfo->height() + font()->height()); @@ -279,520 +268,7 @@ void View::draw() if (!core::localcontrol()) { view_map->set_visible(false); } - - if (core::localcontrol() && (input::mouse_control || input::joystick_control) && - (render::Camera::mode() == render::Camera::Cockpit || render::Camera::mode() == render::Camera::Track)) { - view_center->set_visible(true); - } else { - view_center->set_visible(false); - } -} - -/* -- namespace view ----------------------------------------------- */ - -namespace view -{ - -void init() -{ - // FIXME integrate with libui - draw_ui = core::Cvar::get("draw_ui", "1", core::Cvar::Archive); - draw_ui->set_info("[bool] draw the user interface"); - - targets::init(); - - previousframe = 0; -} - -void shutdown() -{ - targets::shutdown(); -} - -/* - FIXME should be merged with the render passes - and in the bbox pass -*/ - -void draw_entity_world_target(core::Entity *entity) -{ - model::Model *model = entity->model(); - if (!model) - return; - - if (!model->docks().size()) - return; - - float d = math::distance(core::localcontrol()->location(), entity->location()) - entity->radius() - core::localcontrol()->radius(); - if (d > 100.0f) - return; - - gl::enable(GL_DEPTH_TEST); - gl::push(); - gl::translate(entity->location()); - gl::multmatrix(entity->axis()); - - gl::color(0, 1.0f, 1.0f, 1.0f); - - for (model::Model::Docks::iterator dit = model->docks().begin(); dit != model->docks().end(); dit++) { - model::Dock *dock = (*dit); - math::Vector3f maxbox(dock->location()); - math::Vector3f minbox(dock->location()); - - for (size_t i=0; i < 3; i++) { - maxbox[i] += 0.025; - minbox[i] -= 0.025; - } - - // top - gl::begin(gl::LineLoop); - gl::vertex(maxbox.x, maxbox.y, maxbox.z); - gl::vertex(minbox.x, maxbox.y, maxbox.z); - gl::vertex(minbox.x, minbox.y, maxbox.z); - gl::vertex(maxbox.x, minbox.y, maxbox.z); - gl::end(); - - // bottom - gl::begin(gl::LineLoop); - gl::vertex(maxbox.x, maxbox.y, minbox.z); - gl::vertex(minbox.x, maxbox.y, minbox.z); - gl::vertex(minbox.x, minbox.y, minbox.z); - gl::vertex(maxbox.x, minbox.y, minbox.z); - gl::end(); - - gl::begin(gl::Lines); - gl::vertex(maxbox.x, maxbox.y, maxbox.z); - gl::vertex(maxbox.x, maxbox.y, minbox.z); - gl::vertex(minbox.x, maxbox.y, maxbox.z); - gl::vertex(minbox.x, maxbox.y, minbox.z); - gl::vertex(minbox.x, minbox.y, maxbox.z); - gl::vertex(minbox.x, minbox.y, minbox.z); - gl::vertex(maxbox.x, minbox.y, maxbox.z); - gl::vertex(maxbox.x, minbox.y, minbox.z); - gl::end(); - } - - gl::pop(); - gl::disable(GL_DEPTH_TEST); - -} - -void draw_entity_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(ui::root()->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 draw_entity_target(core::Entity *entity, bool is_active_target) -{ - using math::Vector3f; - - // don't draw target if we're very close to it - if (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_entity_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::Camera::frustum_front() + 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_entity_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(ui::root()->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::stringstream 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 << "--"; - } - if (entity->type() == core::Entity::Controlable) { - render::Text::setcolor('B'); - } 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); - } -} - -void draw_hud() -{ - using namespace render; - std::stringstream status; - - // draw a basic HUD - if(core::localplayer()->view()) { - Text::setcolor('N'); //set normal color - Text::draw(render::State::width()-4-Text::fontwidth()*32, render::State::height()-Text::fontheight()*3-4, core::localcontrol()->zone()->name()); - - Text::setcolor('B'); //set bold color - Text::draw(render::State::width() - 4-Text::fontwidth()*32, render::State::height() - Text::fontheight()*2 -4, core::localplayer()->view()->name()); - - } else if (core::localcontrol() && core::localcontrol()->zone()) { - core::Zone *zone = core::localcontrol()->zone(); - - // draw targets - for (core::Zone::Content::iterator it=zone->content().begin(); it != zone->content().end(); it++) { - core::Entity *entity = (*it); - - if (targets::is_legal_target(entity)) { - if (entity == core::localplayer()->mission_target()) { - draw_entity_target(entity, true); - } else if (entity == targets::current()) { - draw_entity_target(entity, true); - } else if (entity->type() == core::Entity::Controlable) { - draw_entity_target(entity, false); - } - } - } - - unsigned int state = core::localcontrol()->eventstate(); - if (state) { - std::stringstream 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); - } - - core::Entity *target = targets::current(); - std::stringstream strdistance; - float d = 0; - float y = 1.0f; - - if (target) { - std::stringstream strtarget; - strtarget << "^B" << target->name() << "\n^B"; - - 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 << " --"; - } - strtarget << '\n'; - Text::draw(render::State::width() - 4-Text::fontwidth()*32, render::State::height() - Text::fontheight()*2 -4, strtarget); - y += 2.0f; - } - - Text::setcolor('N'); //set normal color - Text::draw(render::State::width()-4-Text::fontwidth()*32, render::State::height()-Text::fontheight()*y-4, core::localcontrol()->zone()->name()); - - 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, render::State::height() - 4 - 32, 0); - - glTexCoord2f(1, 0); - gl::vertex(4 + 316, render::State::height() - 4 - 32, 0); - - glTexCoord2f(1, 1); - gl::vertex(4 + 316, render::State::height() - 4 , 0); - - glTexCoord2f(0, 1); - gl::vertex(4, render::State::height() - 4 , 0); - - gl::end(); - - float u = core::localcontrol()->thrust(); - if (core::localcontrol()->eventstate() == core::Entity::Impulse) { - u = 1.0; - } - - if (( u > 0) || (core::localcontrol()->eventstate() == core::Entity::Impulse)) { - - if (core::localcontrol()->eventstate() == core::Entity::Impulse) { - gl::color(0, .8, 0); - } 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, render::State::height() - 4 - 32, 0); - - glTexCoord2f(u, 0); - gl::vertex(4.0f + u * 316.0f, render::State::height() - 4 - 32, 0); - - glTexCoord2f(u, 1); - gl::vertex(4.0f + u * 316.0f, render::State::height() - 4 , 0); - - glTexCoord2f(0, 1); - gl::vertex(4, render::State::height() - 4 , 0); - - gl::end(); - } - - Text::setfont("gui", 14, 24); - Text::setcolor('B'); //set normal color - - std::stringstream speedstr; - speedstr << "^B" << roundf(core::localcontrol()->speed() * 100.0f); - Text::draw( 316+4+10, render::State::height() - 6 -16 - render::Text::fontwidth() /2, speedstr); - - Text::setfont("gui", 12, 18); - Text::setcolor('N'); //set normal color - } -} - -void set_cursor() -{ - if (ui::console()->visible()) { - ui::root()->set_pointer(); - - } else if(core::localplayer()->view() || ui::root()->active()) { - - ui::root()->set_pointer("pointer"); - - } else if (!core::localcontrol()) { - - ui::root()->set_pointer(); - - } else if (client()->view()->map()->hover()) { - - ui::root()->set_pointer("pointer"); - - } else 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); - - if (input::mouse_deadzone) { - ui::root()->input_mouse(render::State::width()/2, render::State::height() /2); - } - - } 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); - } } -void frame(float elapsed) -{ - using namespace render; - - // Clear the color and depth buffers. - gl::clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - render::Stats::clear(); - - if (core::application()->connected() && core::game()->time() && core::localplayer()->zone()) { - render::Camera::frame(elapsed); - render::Camera::frustum(); - - render::draw(elapsed); // draw the world - targets::frame(); // validate current target, render sound - - if (!core::localplayer()->view() && targets::current()) // draw target docks etc - draw_entity_world_target(targets::current()); - - render::Camera::ortho(); - - } else { - render::Camera::ortho(); - } - - gl::color(1.0f, 1.0f, 1.0f, 1.0f); - gl::disable(GL_TEXTURE_2D); - gl::enable(GL_BLEND); - - // draw the user interface - if (draw_ui->value()) { - // draw the hud - TODO move as much as possible into ui:: - if (draw_ui->value() && !ui::root()->active()) { - gl::enable(GL_TEXTURE_2D); - gl::color(1.0f, 1.0f, 1.0f, 1.0f); - Text::setfont("gui", 12, 18); - - // draw the hud - draw_hud(); - } - - set_cursor(); - ui::root()->frame(); - - } else if (ui::console()->visible()) { - ui::console()->event_draw(); - } - - gl::disable(GL_TEXTURE_2D); - gl::disable(GL_BLEND); -} - -} //namespace view - } // namespace client diff --git a/src/client/view.h b/src/client/view.h index 250fa2d..499f6ec 100644 --- a/src/client/view.h +++ b/src/client/view.h @@ -9,6 +9,7 @@ #include "core/zone.h" #include "client/chat.h" +#include "client/hud.h" #include "client/map.h" #include "client/notifications.h" #include "ui/widget.h" @@ -29,7 +30,7 @@ public: protected: /// draw developer info - void draw(); + virtual void draw(); }; /// a widget that shows engine statistics @@ -75,7 +76,6 @@ public: inline Map *map() { return view_map; } inline Chat *chat() { return view_chat; } - inline Notifications *notify() { return view_notify; } protected: @@ -84,34 +84,20 @@ protected: virtual void resize(); private: + HUD *view_hud; Chat *view_chat; DevInfo *view_devinfo; Stats *view_stats; KeyPress *view_keypress; Notifications *view_notify; Map *view_map; - ui::Bitmap *view_center; }; -/// functions to draw the client view -namespace view -{ - /// intialize the view - void init(); - - /// shutdown the view - void shutdown(); - - /// draw the next frame - void frame(float elapsed); - - /// reset OpenGL state - void reset(); +namespace view { - /// clear client-side assets of a zone - void clear_zone(core::Zone *zone); +void draw_hud(); -} // namespace view +} } // namespace client -- cgit v1.2.3