/* view.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 #include #include #include #include #include "client/client.h" #include "client/chat.h" #include "client/console.h" #include "client/input.h" #include "client/targets.h" #include "client/video.h" #include "render/draw.h" #include "render/render.h" #include "render/textures.h" #include "render/camera.h" #include "core/core.h" #include "core/stats.h" #include "math/mathlib.h" #include "sys/sys.h" namespace client { core::Cvar *draw_ui = 0; core::Cvar *draw_stats = 0; core::Cvar *draw_location = 0; core::Cvar *draw_keypress = 0; core::Cvar *ui_pointercolor = 0; core::Cvar *ui_pointerhovercolor =0; namespace view { const size_t fps_counter_size = 32; // fps is the average of 32 frames float fps_counter_time[fps_counter_size]; size_t fps_counter_index = 0; const size_t net_counter_size = 128; float net_counter_time[net_counter_size]; size_t net_counter_traffic[net_counter_size]; size_t net_counter_index; void init() { draw_stats = core::Cvar::get("draw_stats", "0", core::Cvar::Archive); draw_stats->set_info("[bool] draw network and render statistics"); draw_location = core::Cvar::get("draw_location", "0", core::Cvar::Archive); draw_location->set_info("[bool] draw world location"); draw_ui = core::Cvar::get("draw_ui", "1", core::Cvar::Archive); draw_ui->set_info("[bool] draw the user interface"); draw_keypress = core::Cvar::get("draw_keypress", "0", core::Cvar::Archive); draw_keypress->set_info("[bool] draw keypress key names"); ui_pointercolor = core::Cvar::get("ui_pointercolor", "0 .5 0", core::Cvar::Archive); ui_pointercolor->set_info("[r g b] mouse pointer color"); ui_pointerhovercolor = core::Cvar::get("ui_pointerhovercolor", "0 1 0", core::Cvar::Archive); ui_pointerhovercolor->set_info("[r g b] mouse pointer hover color"); targets::init(); for (size_t i =0; i < fps_counter_size; i++) fps_counter_time[i] = 0.0f; for (size_t i = 0; i < net_counter_size; i++) net_counter_traffic[i] = 0; } void shutdown() { targets::shutdown(); } void draw_loader() { using namespace render; render::Textures::bind("bitmaps/loader"); gl::begin(gl::Quads); glTexCoord2f(0.0f, 0.0f); gl::vertex(0,0, 0); glTexCoord2f(1.0f, 0.0f); gl::vertex(video::width,0,0); glTexCoord2f(1.0f, 1.0f); gl::vertex(video::width,video::height,0); glTexCoord2f(0.0f, 1.0f); gl::vertex(0,video::height,0); gl::end(); } void draw_status() { using namespace render; std::stringstream status; if (core::game()) { int minutes = (int) floorf(core::game()->clientframetime() / 60.0f); int seconds = (int) floorf( core::game()->clientframetime() - (float) minutes* 60.0f); status << "^Ntime ^B" << std::setfill(' ') << std::setw(3) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds; Text::draw(video::width-Text::fontwidth()*12-4, Text::fontheight()+ 4, status); } // print stats if desired if (draw_stats && draw_stats->value()) { // average fps fps_counter_time[fps_counter_index] = core::application()->time(); fps_counter_index = (fps_counter_index + 1 ) % fps_counter_size; float min_time = core::application()->time(); for (size_t i=0; i < fps_counter_size; i++) if (fps_counter_time[i] < min_time) min_time = fps_counter_time[i]; float fps = 0.0f; float t = (core::application()->time() - min_time); if (t > 0) { fps = roundf(((float) fps_counter_size - 1.0f) / t); } std::stringstream stats; stats << "^Nfps ^B" << std::setw(6) << fps << "\n"; if (core::application()->connected()) { stats << "^Ntris ^B" << std::setw(5) << render::Stats::tris << "\n"; stats << "^Nquads ^B" << std::setw(5) << render::Stats::quads << "\n"; if (core::Stats::network_bytes_sent + core::Stats::network_bytes_received) { net_counter_traffic[net_counter_index] = core::Stats::network_bytes_sent + core::Stats::network_bytes_received; net_counter_time[net_counter_index] = core::application()->time(); size_t index_max = net_counter_index; net_counter_index = (net_counter_index + 1) % net_counter_size; size_t index_min = net_counter_index; float d = net_counter_time[index_max] - net_counter_time[index_min]; if (d > 0) { float traffic = net_counter_traffic[index_max] - net_counter_traffic[index_min]; stats << "^Nnet ^B" << std::setw(6) << roundf( (float) traffic / d ) << "\n"; } } } Text::draw(video::width-Text::fontwidth()*12-4, 4 + Text::fontheight()*2, stats); } // draw a basic HUD if (core::localcontrol()) { status.str(""); status << "^Nthrust ^B" << std::setfill(' ') << std::setw(5) << std::fixed << std::setprecision(2) << core::localcontrol()->thrust() << " "; status << "^Nspeed ^B" << std::setfill(' ') << std::setw(5) << std::fixed << std::setprecision(2) << core::localcontrol()->speed(); Text::draw(4, video::height - Text::fontheight() -4, status); if (draw_location->value()) { std::stringstream location; location << "^Nloc ^B" << std::fixed << std::setprecision(2) << std::setfill(' ') << std::setw(7) << core::localcontrol()->location().x << " " << std::setw(7) << core::localcontrol()->location().y << " " << std::setw(7) << core::localcontrol()->location().z; Text::draw(4, video::height - Text::fontheight()*2 -4, location); } float y = 1.0f; core::Entity *entity = targets::current(); if (entity) { std::stringstream target; target << "^B" << entity->name() << "\n"; target << "^Ndist ^B"; math::Vector3f v = entity->state()->location() - core::localcontrol()->state()->location(); float d = v.length() - entity->radius() - core::localcontrol()->radius(); if (d > 0 ) target << std::fixed << std::setprecision(2) << std::setfill(' ') << std::setw(8) << d; else target << " --"; Text::draw(video::width - 4-Text::fontwidth()*32, video::height - Text::fontheight()*2 -4, target); y = 3.0f; } Text::draw(video::width-4-Text::fontwidth()*32, video::height-Text::fontheight()*y-4, core::localcontrol()->zone()->name()); } if (draw_keypress->value() && input::last_key_pressed()) { Text::setcolor('F'); //set fancy color Text::draw(video::width-4-Text::fontwidth()*6, video::height-Text::fontheight()-4, input::last_key_pressed()->name()); } } void draw_cursor() { if (!core::localcontrol() || console()->visible()) return; float angle = 0; float pointer_size = 48.0f; float x = (float) input::mouse_position_x() - (pointer_size / 2.0f); float y = (float) input::mouse_position_y() - (pointer_size / 2.0f); bool cursor_animated = false; math::Color color(1.0, 0.5); if (render::Camera::mode() == render::Camera::Overview) { render::Textures::bind("bitmaps/pointers/aim"); } else { // draw center cursor in Cockpit and Track mode if (input::mouse_control && (render::Camera::mode() == render::Camera::Cockpit || render::Camera::mode() == render::Camera::Track)) { if (ui_pointercolor) { std::stringstream colorstr(ui_pointercolor->str()); colorstr >> color; } render::Textures::bind("bitmaps/pointers/center"); float cx = (video::width - pointer_size) /2; float cy = (video::height - pointer_size) /2; render::gl::color(color); render::gl::begin(render::gl::Quads); glTexCoord2f(0,0 ); render::gl::vertex(cx,cy,0.0f); glTexCoord2f(1, 0); render::gl::vertex(cx+pointer_size, cy, 0.0f); glTexCoord2f(1, 1); render::gl::vertex(cx+pointer_size, cy+pointer_size, 0.0f); glTexCoord2f(0, 1); render::gl::vertex(cx, cy+pointer_size, 0.0f); render::gl::end(); } if (targets::hover()) { if (ui_pointerhovercolor) { std::stringstream colorstr(ui_pointerhovercolor->str()); colorstr >> color; } render::Textures::bind("bitmaps/pointers/target"); cursor_animated = true; } else if (input::mouse_control) { if (ui_pointercolor) { std::stringstream colorstr(ui_pointercolor->str()); colorstr >> color; } render::Textures::bind("bitmaps/pointers/control"); if (!input::mouse_deadzone) { x = input::mouse_position_x() - (pointer_size /2); y = input::mouse_position_y() - (pointer_size /2); } else { x = (video::width - pointer_size) /2; y = (video::height - pointer_size) /2; } } else { render::Textures::bind("bitmaps/pointers/aim"); } } if (cursor_animated) { render::gl::push(); render::gl::translate(x+pointer_size/2, y+pointer_size/2, 0.0f); angle = core::application()->time()* 0.75f - floorf(core::application()->time() * 0.75f); angle *= 360.0f; render::gl::rotate(angle, math::Vector3f(0, 0, 1.0f)); render::gl::translate(-x-pointer_size/2, -y-pointer_size/2, 0.0f); } render::gl::color(color); render::gl::begin(render::gl::Quads); glTexCoord2f(0,0 ); render::gl::vertex(x,y,0.0f); glTexCoord2f(1, 0); render::gl::vertex(x+pointer_size, y, 0.0f); glTexCoord2f(1, 1); render::gl::vertex(x+pointer_size, y+pointer_size, 0.0f); glTexCoord2f(0, 1); render::gl::vertex(x, y+pointer_size, 0.0f); render::gl::end(); if (cursor_animated) { render::gl::pop(); } } void reset() { using namespace render; // set clear color gl::clearcolor(0.0f, 0.0f, 0.0f, 1.0f); // load identity matrices gl::matrixmode(GL_MODELVIEW); gl::loadidentity(); gl::matrixmode(GL_MODELVIEW); gl::loadidentity(); // shading model: Gouraud (smooth, the default) gl::shademodel(GL_SMOOTH); //gl::shademodel(GL_FLAT); // lighting settings for the default light GL_LIGHT0 GLfloat light_position[] = { 0.0, 0.0, 0.0, 1.0 }; GLfloat ambient_light[] = { 0.01f, 0.01f, 0.01f, 1.0f }; GLfloat diffuse_light[] = { 0.2f, 0.2f, 0.2f, 1.0f }; GLfloat specular_light[] = { 0.2f, 0.2f, 0.2f, 1.0f }; glLightfv(GL_LIGHT0, GL_POSITION, light_position); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_light); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_light); glLightfv(GL_LIGHT0, GL_SPECULAR, specular_light); // GL_LIGHT0 is always enabled gl::enable(GL_LIGHT0); // color tracking glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); // material settings GLfloat specular_reflectance[] = { 0.2f, 0.2f, 0.2f, 1.0f }; glMaterialfv(GL_FRONT, GL_SPECULAR, specular_reflectance); glMateriali(GL_FRONT, GL_SHININESS, 128); // shininess 1-128 // alpha blending function gl::blendfunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl::disable(GL_LIGHTING); gl::disable(GL_COLOR_MATERIAL); gl::cullface(GL_BACK); gl::frontface(GL_CCW); gl::disable(GL_CULL_FACE); gl::disable(GL_DEPTH_TEST); gl::disable(GL_BLEND); gl::disable(GL_TEXTURE_2D); } void frame(float seconds) { using namespace render; // flush console messages console()->flush(); // 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()->serverframetime()) { render::draw(seconds); // draw the world targets::frame(); if (draw_ui->value()) { targets::draw_target(); } } // switch to orthographic projection to draw the GUI gl::matrixmode(GL_PROJECTION); gl::loadidentity(); glOrtho(0, video::width, video::height, 0, -1024.0f, 1024.0f); gl::matrixmode(GL_MODELVIEW); gl::loadidentity(); gl::enable(GL_TEXTURE_2D); gl::color(1.0f, 1.0f, 1.0f, 1.0f); if (!core::application()->connected()) { // draw the loader bitmap draw_loader(); // force console on if not connected if (!console()->visible()) console()->toggle(); } gl::enable(GL_BLEND); // draw text elements if (draw_ui->value()) { Text::setfont("bitmaps/fonts/gui", 12, 18); // draw the player status draw_status(); // draw the chat box chat::draw(); // draw the mouse cursor draw_cursor(); } // draw console or notifications Text::setfont("bitmaps/fonts/gui", 12, 18); console()->draw(); gl::disable(GL_TEXTURE_2D); gl::disable(GL_BLEND); } } //namespace view } // namespace client