/* 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 hours = (int) sys::time() / 3600; int minutes = (int)(sys::time() - 3600*hours) / 60; int seconds = (int)(sys::time() - 3600*hours - 60 *minutes); status << "clock " << std::setfill('0') << std::setw(2) << hours << ":" << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds; minutes = (int) floorf(core::application()->time() / 60.0f); seconds = (int) floorf(core::application()->time() - (float) minutes* 60.0f); status << " time " << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds; draw_text(CHARWIDTH, 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"; draw_text(video::width-CHARWIDTH*12, CHARHEIGHT*2, stats); } // print the version number in the upper right corner gl::color(0.0f, 1.0f, 0.0f, 1.0f); std::string version("ver. "); version.append(core::version()); draw_text(video::width-(version.size()+1)*CHARWIDTH, 4, version); // draw notifications gl::color(1.0f, 1.0f, 1.0f, 1.0f); size_t n = console::notify_pos % MAXNOTIFYLINES; int h = 4 + CHARHEIGHT; for (size_t l = 0; l < MAXNOTIFYLINES; l++) { if (console::notify_text[n].size() > 2 && console::notify_time[n] + 4 > core::application()->time()) { if (console::notify_text[n][0] == '?') gl::color(0.7f,0.7f,0.7f, 1.0f); else if (console::notify_text[n][0] == '*') gl::color(1.0f,1.0f,0.0f, 1.0f); else if (console::notify_text[n][0] == '!') gl::color(1.0f,0.0f,0.0f, 1.0f); else gl::color(1.0f,1.0f,1.0f, 1.0f); draw_text(CHARWIDTH, h, console::notify_text[n].substr(2)); h += CHARHEIGHT; } n = (n+1) % MAXNOTIFYLINES; } // draw a basic HUD if (core::localcontrol()) { 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(); draw_text(CHARWIDTH, video::height - CHARHEIGHT -4, status); } } 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()) { // 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 render::Textures::bind("bitmaps/conchars"); console::draw(); chat::draw(); draw_status(); // draw the mouse cursor draw_cursor(); gl::disable(GL_TEXTURE_2D); } } //namespace view } // namespace client