/*] Copyright (c) 2009-2010, Charles McGarvey [************************** **] All rights reserved. * * vi:ts=4 sw=4 tw=75 * * Distributable under the terms and conditions of the 2-clause BSD license; * see the file COPYING for a complete text of the license. * **************************************************************************/ #include #include "dispatcher.hh" #include "image.hh" #include "log.hh" #include "settings.hh" #include "video.hh" namespace moof { video::video(const std::string& caption) { video::caption(caption); init(); } video::video(const class attributes& attribs) : attributes_(attribs) { init(); } video::video(const std::string& caption, const class attributes& attribs) : attributes_(attribs) { video::caption(caption); init(); } void video::init() { context_ = 0; flags_ = 0; fullscreen(attributes_.is_fullscreen); resizable(attributes_.is_resizable); set_opengl_attributes(); cursor_visible(attributes_.is_cursor_visible); cursor_captured(attributes_.is_cursor_captured); mode(attributes_.mode); if (!current_) make_current(); } void video::recreate_context() { SDL_FreeSurface(context_); context_ = 0; mode(attributes_.mode); } void video::set_opengl_attributes() { SDL_GL_SetAttribute(SDL_GL_RED_SIZE, attributes_.color_buffer[0]); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, attributes_.color_buffer[1]); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, attributes_.color_buffer[2]); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, attributes_.color_buffer[3]); SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, attributes_.frame_buffer); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, attributes_.is_double_buffer); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, attributes_.depth_buffer); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, attributes_.stencil_buffer); SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, attributes_.accumulator_buffer[0]); SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, attributes_.accumulator_buffer[1]); SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE, attributes_.accumulator_buffer[2]); SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, attributes_.accumulator_buffer[3]); SDL_GL_SetAttribute(SDL_GL_STEREO, attributes_.is_stereo); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, attributes_.multisample_buffers); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, attributes_.multisample_samples); SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, attributes_.is_swap_control); SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, attributes_.is_hardware_only); } video::~video() { SDL_FreeSurface(context_); if (current_ == this) current_ = 0; } class video::attributes video::attributes() const { return attributes_; } void video::mode(const int mode[3]) { if (mode != attributes_.mode || !context_) { if (context_) SDL_FreeSurface(context_); context_ = SDL_SetVideoMode(mode[0], mode[1], mode[2], SDL_OPENGL | flags_); if (context_) { attributes_.mode[0] = mode[0]; attributes_.mode[1] = mode[1]; attributes_.mode[2] = mode[2]; #if !defined(linux) && !defined(__linux) && !defined(__linux__) log_info("video context recreated"); dispatcher::global().dispatch("video.newcontext"); #endif } else { throw std::runtime_error("bad video mode attempted"); } } } void video::resize(int width, int height) { int mode[] = {width, height, attributes_.mode[2]}; video::mode(mode); } bool video::iconify() { return SDL_WM_IconifyWindow(); } void video::caption(const std::string& caption) { SDL_WM_SetCaption(caption.c_str(), 0); } std::string video::caption() const { char* caption; SDL_WM_GetCaption(&caption, 0); return std::string(caption); } void video::fullscreen(bool full) { if (full != fullscreen() || !context_) { if (context_) { flags_ ^= SDL_FULLSCREEN; #if defined(linux) || defined(__linux) || defined(__linux__) if (SDL_WM_ToggleFullScreen(context_) == 0) #endif recreate_context(); } else { if (full) flags_ |= SDL_FULLSCREEN; else flags_ &= ~SDL_FULLSCREEN; } } } bool video::fullscreen() const { return flags_ & SDL_FULLSCREEN; } void video::toggle_fullscreen() { fullscreen(!fullscreen()); } void video::resizable(bool is_resizable) { if (is_resizable != resizable() || !context_) { if (context_) { flags_ ^= SDL_RESIZABLE; recreate_context(); } else { if (is_resizable) flags_ |= SDL_RESIZABLE; else flags_ &= ~SDL_RESIZABLE; } } } bool video::resizable() const { return flags_ & SDL_RESIZABLE; } void video::toggle_resizable() { resizable(!resizable()); } void video::cursor_visible(bool is_cursor_visible) { SDL_ShowCursor(is_cursor_visible? SDL_ENABLE : SDL_DISABLE); } bool video::cursor_visible() const { return (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE); } void video::toggle_cursor_visible() { cursor_visible(!cursor_visible()); } bool video::cursor_captured() const { return (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON); } void video::cursor_captured(bool is_cursor_captured) { SDL_WM_GrabInput(is_cursor_captured? SDL_GRAB_ON : SDL_GRAB_OFF); } void video::toggle_cursor_captured() { cursor_captured(!cursor_captured()); } void video::swap() { SDL_GL_SwapBuffers(); } int video::width() const { return context_->w; } int video::height() const { return context_->h; } void video::make_current() const { current_ = const_cast(this); } video::attributes::attributes() { init(); } video::attributes::attributes(const settings& settings) { init(); std::vector colors; settings.get("colorbuffers", colors); if (colors.size() > 0) color_buffer[0] = colors[0]; if (colors.size() > 1) color_buffer[1] = colors[1]; if (colors.size() > 2) color_buffer[2] = colors[2]; if (colors.size() > 3) color_buffer[3] = colors[3]; settings.get("framebuffer", frame_buffer); settings.get("doublebuffer", is_double_buffer); settings.get("depthbuffer", depth_buffer); settings.get("stencilbuffer", stencil_buffer); std::vector accum; settings.get("accumbuffers", accum); if (accum.size() > 0) accumulator_buffer[0] = accum[0]; if (accum.size() > 1) accumulator_buffer[1] = accum[1]; if (accum.size() > 2) accumulator_buffer[2] = accum[2]; if (accum.size() > 3) accumulator_buffer[3] = accum[3]; settings.get("stereo", is_stereo); settings.get("multiesamplebuffers", multisample_buffers); settings.get("multiesamplesamples", multisample_samples); settings.get("swapcontrol", is_swap_control); settings.get("hardwareonly", is_hardware_only); settings.get("fullscreen", is_fullscreen); settings.get("resizable", is_resizable); settings.get("showcursor", is_cursor_visible); settings.get("capturecursor", is_cursor_captured); std::vector dimensions; settings.get("videomode", dimensions); if (dimensions.size() > 1) { mode[0] = dimensions[0]; mode[1] = dimensions[1]; } else if (is_fullscreen && backend::is_initialized()) { SDL_Rect** modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE); if (modes == (SDL_Rect**)0) { throw std::runtime_error("can't find appropriate video mode"); } else if (modes == (SDL_Rect**)-1) { log_warning("any resolution allowed; choosing default 800x600"); mode[0] = 800; mode[1] = 600; } else { mode[0] = (*modes)->w; mode[1] = (*modes)->h; log_info << "choosing native resolution: " << mode[0] << "x" << mode[1] << std::endl; } } if (dimensions.size() > 2) mode[2] = dimensions[2]; } void video::attributes::init() { // set some sane GL and window defaults (see SDL_video.c:217) color_buffer[0] = 3; color_buffer[1] = 3; color_buffer[2] = 2; color_buffer[3] = 0; frame_buffer = 0; is_double_buffer = true; depth_buffer = 16; stencil_buffer = 0; accumulator_buffer[0] = 0; accumulator_buffer[1] = 0; accumulator_buffer[2] = 0; accumulator_buffer[3] = 0; is_stereo = false; multisample_buffers = 0; multisample_samples = 0; is_swap_control = false; is_hardware_only = false; mode[0] = 640; mode[1] = 480; mode[2] = 0; is_fullscreen = false; is_resizable = false; is_cursor_visible = true; is_cursor_captured = false; } video* video::current_ = 0; // most recently instantiated instance } // namespace moof