/* client/video.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 "core/gameserver.h" #include "client/video.h" #include "client/input.h" #include "client/client.h" #include "client/targets.h" #include "render/render.h" #include "render/gl.h" #include "filesystem/filesystem.h" #include "sys/sys.h" #include "ui/ui.h" #include "ui/paint.h" #include using namespace render; namespace client { /* -- engine variables --------------------------------------------- */ core::Cvar *r_width = 0; core::Cvar *r_height = 0; core::Cvar *r_windowwidth = 0; core::Cvar *r_windowheight = 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; core::Cvar *draw_clock = 0; namespace video { float fullscreen = 0; int bpp = 0; int flags = 0; int width = 0; int height = 0; int width_prev = 0; int height_prev = 0; // default resolution and window size const int width_default = 1024; const int height_default = 768; std::string loader_message; bool is_loading = false; void set_caption() { // set window caption std::string window_title(core::name()); window_title += ' '; window_title.append(core::version()); SDL_WM_SetCaption(window_title.c_str(), core::name().c_str()); } bool init() { con_print << "^BInitializing video..." << std::endl; // initialize engine variables r_width = core::Cvar::get("r_width", width_default, core::Cvar::Archive); r_width->set_info("[int] video resolution width"); r_height = core::Cvar::get("r_height", height_default, core::Cvar::Archive); r_height->set_info("[int] video resolution height"); r_windowwidth = core::Cvar::get("r_windowwidth", width_default, core::Cvar::Archive); r_windowwidth->set_info("[int] window width in windowed mode"); r_windowheight = core::Cvar::get("r_windowheight", height_default, core::Cvar::Archive); r_windowheight->set_info("[int] window height in windowed mode"); 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_clock = core::Cvar::get("draw_clock", "0", core::Cvar::Archive); draw_clock->set_info("[int] draw clock (0=Off, 1=12hr, 2=24hr)"); 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; } // set the window icon /* * FIXME * store the icon as binary data * and use SDL_CreateRGBSurfaceFrom to create the icon */ filesystem::File *iconfile = filesystem::open("bitmaps/icon.bmp"); if (iconfile) { std::string iconfilename = iconfile->path(); iconfilename.append(iconfile->name()); filesystem::close(iconfile); con_debug << " setting window icon " << iconfilename << std::endl; SDL_Surface *image = SDL_LoadBMP(iconfilename.c_str()); if (image) { Uint32 colorkey = SDL_MapRGB(image->format, 255, 0, 255); SDL_SetColorKey(image, SDL_SRCCOLORKEY, colorkey); SDL_WM_SetIcon(image, NULL); } } const SDL_VideoInfo* sdl_videoinfo = SDL_GetVideoInfo(); if (!sdl_videoinfo) { con_error << "SDL_GetVideoInfo() failed: " << SDL_GetError() << std::endl; return false; } bpp = sdl_videoinfo->vfmt->BitsPerPixel; if (bpp == 32) { SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); } else if (bpp == 24) { SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 6); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 6); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 6); } else if (bpp == 16) { SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 4); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 4); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 4); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 4); } else { con_warn << "Display depth " << bpp << " is not supported!" << std::endl; } SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); width_prev = width; height_prev = height; width = (int) r_width->value(); height = (int) r_height->value(); fullscreen = r_fullscreen->value(); if (r_fullscreen->value()) { flags = SDL_OPENGL | SDL_FULLSCREEN; } else { if (r_windowwidth->value() && r_windowheight->value()) { width = (int) r_windowwidth->value(); height = (int) r_windowheight->value(); } flags = SDL_OPENGL; #ifndef _WIN32 flags |= SDL_RESIZABLE; #endif } if (!SDL_SetVideoMode(width, height, bpp, flags)) { con_warn << "Failed to set video mode " << width << "x" << height << "x" << bpp << "bpp" << std::endl; if (width_prev && height_prev) { width = width_prev; height = height_prev; if (!SDL_SetVideoMode(width, height, bpp, flags)) { con_error << "Failed to restore video mode " << width << "x" << height << "x" << bpp << "bpp" << std::endl; return false; } } else return false; } con_print << " video mode " << width << "x" << height << "x" << bpp << "bpp " << (fullscreen ? "fullscreen " : "window") << std::endl; #ifdef HAVE_DEBUG_MESSAGES int red, green, blue, alpha, depth; SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &red); SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &green); SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &blue); SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &alpha); SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &depth); con_debug << " visual r: " << red << " g: " << green << " blue: " << blue << " alpha: " << alpha << " depth: " << depth << std::endl; #endif // HAVE_DEBUG_MESSAGES // set window caption set_caption(); // save window width and height if (fullscreen) { (*r_width) = width; (*r_height) = height; } else { (*r_windowwidth) = width; (*r_windowheight) = height; } // resize user interface ui::root()->set_size((float) width, (float) height); ui::root()->event_resize(); // to grab or not to grab core::Cvar *input_grab = core::Cvar::find("input_grab"); if (ui::console()->visible() || (input_grab && input_grab->value())) { SDL_WM_GrabInput(SDL_GRAB_OFF); SDL_ShowCursor(SDL_ENABLE); } else { SDL_WM_GrabInput(SDL_GRAB_ON); SDL_ShowCursor(SDL_DISABLE); } // initialize renderer render::init(width, height); // apply render options ui::root()->load_settings(); // initialize target drawer targets::init(); return true; } void resize(int w, int h) { if (fullscreen) return; if (w < 320) w = 320; if (h < 200) h = 200; if (SDL_SetVideoMode(w, h, bpp, flags)) { render::resize(w, h); ui::root()->set_size(w, h); ui::root()->event_resize(); } else { con_warn << "Could not resize window!" << std::endl; } } void restart() { shutdown(); // clear models and materials /* resetting the rednder subsystem will force a reload of all materials */ model::Model::clear(); model::Material::clear(); if (!init()) { client()->quit(1); } model::Material::init(); render::load(); input::reset(); } void set_loader_message(const std::string message) { loader_message.assign(message); if (is_loading) frame_loader(); } void set_loader_message(const char *message) { if (message) loader_message.assign(message); else loader_message.clear(); if (is_loading) frame_loader(); } void draw_loader() { render::Camera::ortho(); gl::enable(GL_BLEND); gl::color(1.0f, 1.0f, 1.0f, 1.0f); math::Vector2f pos; math::Vector2f size(render::State::width(), render::State::height()); ui::Paint::draw_bitmap(pos, size, "bitmaps/loader"); if (loader_message.size()) { using render::Text; gl::enable(GL_TEXTURE_2D); Text::setfont("gui", 12, 18); Text::setcolor('N'); //set normal color Text::draw(Text::fontwidth(), Text::fontheight(), loader_message); gl::disable(GL_TEXTURE_2D); } gl::disable(GL_BLEND); is_loading = true; } void frame_loader() { // Clear the color and depth buffers. gl::clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); draw_loader(); SDL_GL_SwapBuffers(); } void frame(float elapsed) { // detect fullscreen/windowed mode switch if (fullscreen != r_fullscreen->value()) restart(); using namespace render; is_loading = false; // Clear the color and depth buffers. gl::clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); render::Stats::clear(); if (core::application()->connected()) { if (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(); client()->mainwindow()->show(); } else { draw_loader(); client()->mainwindow()->hide(); } } else { client()->mainwindow()->hide(); 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()) { ui::root()->frame(); } else if (ui::console()->visible()) { ui::console()->event_draw(); } gl::disable(GL_TEXTURE_2D); gl::disable(GL_BLEND); SDL_GL_SwapBuffers(); } void shutdown() { con_print << "^BShutting down video..." << std::endl; targets::shutdown(); render::shutdown(); width = 0; height = 0; SDL_QuitSubSystem(SDL_INIT_VIDEO); } } // namespace video } // namespace client