/* 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/camera.h" #include "client/chat.h" #include "client/console.h" #include "client/input.h" #include "client/video.h" #include "render/draw.h" #include "render/render.h" #include "render/textures.h" #include "core/core.h" #include "core/stats.h" #include "math/mathlib.h" #include "sys/sys.h" namespace client { core::Cvar *draw_stats = 0; core::Cvar *draw_crosshaircolor = 0; namespace view { float fps = 0; void init() { camera::init(); draw_stats = core::Cvar::get("draw_stats", "0", core::Cvar::Archive); draw_crosshaircolor = core::Cvar::get("draw_crosshaircolor", "1 1 1", core::Cvar::Archive); } void shutdown() { camera::shutdown(); } void reset() { using namespace render; // set clear color gl::clearcolor(0.0f, 0.0f, 0.0f, 1.0f); // shading model: Gouraud (smooth, the default) gl::shademodel(GL_SMOOTH); //gl::shademodel(GL_FLAT); // lighting GLfloat light_position[] = { 0.0, 0.0, 0.0, 1.0 }; GLfloat ambient_light[] = { 0.2f, 0.2f, 0.2f, 1.0f }; GLfloat diffuse_light[] = { 0.4f, 0.4f, 0.4f, 1.0f }; GLfloat specular_light[] = { 0.4f, 0.4f, 0.4f, 1.0f }; GLfloat specular_reflectance[] = { 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); // color tracking glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); glMaterialfv(GL_FRONT, GL_SPECULAR, specular_reflectance); glMateriali(GL_FRONT, GL_SHININESS, 128); // shininess 1-128 gl::disable(GL_LIGHTING); gl::enable(GL_LIGHT0); gl::disable(GL_COLOR_MATERIAL); // culling gl::cullface(GL_BACK); gl::frontface(GL_CCW); gl::disable(GL_CULL_FACE); // depth gl::depthmask(GL_TRUE); gl::disable(GL_DEPTH_TEST); // alpha-blending gl::blendfunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl::enable(GL_BLEND); // client state } void draw_loader() { using namespace render; render::Textures::bind("bitmaps/loader"); gl::color(1.0f, 1.0f, 1.0f, 1.0f); 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; if (console::visible()) return; // print the status in the upper left corner gl::color(1.0f, 1.0f, 1.0f, 1.0f); std::stringstream status; /* int minutes = (int) floorf(core::application()->time() / 60.0f); int seconds = (int) floorf(core::application()->time() - (float) minutes* 60.0f); */ if (core::game()) { int minutes = (int) floorf(core::game()->clientframetime() / 60.0f); int seconds = (int) floorf( core::game()->clientframetime() - (float) minutes* 60.0f); status << "time " << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds; Text::draw(4, 4, status); } // print stats if desired if (draw_stats && draw_stats->value()) { std::stringstream stats; stats << "fps " << std::setw(6) << fps << "\n"; if (core::application()->connected()) { stats << "tris " << std::setw(5) << render::Stats::tris << "\n"; stats << "quads " << std::setw(5) << render::Stats::quads << "\n"; } stats << "tx "<< std::setw(5) << (core::Stats::network_bytes_sent >> 10) << "\n"; stats << "rx "<< std::setw(5) << (core::Stats::network_bytes_received >> 10) << "\n"; Text::draw(video::width-Text::fontwidth()*12, video::height - Text::fontheight()*8, stats); } // draw a basic HUD if (core::localcontrol()) { gl::color(1.0f,1.0f,1.0f, 1.0f); status.str(""); status << "thrust " << std::setfill(' ') << std::setw(5) << std::fixed << std::setprecision(2) << core::localcontrol()->thrust() << " "; status << "speed " << std::setfill(' ') << std::setw(5) << std::fixed << std::setprecision(2) << core::localcontrol()->speed(); Text::draw(4, video::height - Text::fontheight() -4, status); } } void draw_notify() { using namespace render; if (console::visible()) return; // draw notifications gl::color(1.0f, 1.0f, 1.0f, 1.0f); size_t width = (size_t) ((video::width - 8) / Text::fontwidth()); size_t n = console::notify_pos % MAXNOTIFYLINES; float h = 4 + 2*Text::fontheight(); for (size_t l = 0; l < MAXNOTIFYLINES; l++) { if (console::notify_text[n].size() > 2 && console::notify_time[n] + 4 > core::application()->time()) { std::string line(console::notify_text[n]); if (line[0] == '?') gl::color(0.7f,0.7f,0.7f, 1.0f); else if (line[0] == '*') gl::color(1.0f,1.0f,0.0f, 1.0f); else if (line[0] == '!') gl::color(1.0f,0.0f,0.0f, 1.0f); else gl::color(1.0f,1.0f,1.0f, 1.0f); line.erase(0,2); std::deque lines; while (line.size() > width) { Text::draw(4, h, line.substr(0, width)); line.erase(0, width); h += Text::fontheight(); } if (line.size()) { Text::draw(4, h, line); h += Text::fontheight(); } } n = (n+1) % MAXNOTIFYLINES; } } void draw_cursor() { if (!core::localcontrol() || console::visible()) return; float crosshair_size = 48.0f; float x = input::mouse_x - (crosshair_size /2); float y = input::mouse_y - (crosshair_size /2); using namespace render; render::Textures::bind("bitmaps/crosshair"); math::Color color; if (draw_crosshaircolor && draw_crosshaircolor->value()) { std::stringstream colorstr(draw_crosshaircolor->str()); colorstr >> color; } if (cl_mousecontrol->value() && input::mouse_deadzone) color.a = 0.3f; else color.a = 0.5f; gl::color(color); gl::begin(gl::Quads); glTexCoord2f(0,0 ); gl::vertex(x,y,0.0f); glTexCoord2f(1, 0); gl::vertex(x+crosshair_size, y, 0.0f); glTexCoord2f(1, 1); gl::vertex(x+crosshair_size, y+crosshair_size, 0.0f); glTexCoord2f(0, 1); gl::vertex(x, y+crosshair_size, 0.0f); gl::end(); } void frame(float seconds) { using namespace render; // calculate frames per second if (seconds > 0.0f) fps = floorf(1.0f / seconds); else fps = 9999; // flush console messages console::flush(); // Clear the color and depth buffers. gl::clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (core::application()->connected() && core::game()->serverframetime()) { // Change to the projection matrix and set our viewing volume. gl::matrixmode(GL_PROJECTION); gl::loadidentity(); // FIXME width must always be one const float frustumsize = 0.5f; gl::frustum(-frustumsize*video::aspect, frustumsize*video::aspect, -frustumsize, frustumsize, 1.0f, 1024.0f); gl::matrixmode(GL_MODELVIEW); // map world to screen coordinates gl::loadidentity(); camera::draw(seconds); // draw the current camera transformation render::draw(camera::axis, camera::eye, camera::target, seconds); // draw the world } // switch to ortographic projection to draw the GUI gl::matrixmode(GL_PROJECTION); gl::loadidentity(); glOrtho(0, video::width, video::height, 0, -1000.0f, 1000.0f); gl::matrixmode(GL_MODELVIEW); gl::loadidentity(); gl::enable(GL_TEXTURE_2D); if (!core::application()->connected()) { // draw the loader bitmap draw_loader(); } // draw text elements // FIXME width and height should be derived from texture size Text::setfont("bitmaps/fonts/console", 12, 18); console::draw(); draw_notify(); chat::draw(); Text::setfont("bitmaps/fonts/gui", 16, 24); draw_status(); // draw the mouse cursor draw_cursor(); gl::disable(GL_TEXTURE_2D); } } //namespace view } // namespace client