/*] 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 "Dispatch.hh" #include "Error.hh" #include "Image.hh" #include "Log.hh" #include "Settings.hh" #include "Video.hh" namespace Mf { Video::Video() { init(); } Video::Video(const Attributes& attribs) : mAttribs(attribs) { init(); } void Video::init() { Error error = Backend::getError(); if (error) error.raise(); mContext = 0; mFlags = 0; setFull(mAttribs.fullscreen); setResizable(mAttribs.resizable); setOpenGLAttributes(); setCaption(mAttribs.caption); setIcon(); setCursorVisible(mAttribs.cursorVisible); setCursorGrab(mAttribs.cursorGrab); setVideoMode(mAttribs.mode); if (!gCurrentVideo) makeCurrent(); } void Video::recreateContext() { SDL_FreeSurface(mContext); mContext = 0; setVideoMode(mAttribs.mode); } void Video::setOpenGLAttributes() { SDL_GL_SetAttribute(SDL_GL_RED_SIZE, mAttribs.colorBuffer[0]); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, mAttribs.colorBuffer[1]); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, mAttribs.colorBuffer[2]); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, mAttribs.colorBuffer[3]); SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, mAttribs.frameBuffer); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, mAttribs.doubleBuffer); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, mAttribs.depthBuffer); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, mAttribs.stencilBuffer); SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, mAttribs.accumBuffer[0]); SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, mAttribs.accumBuffer[1]); SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE, mAttribs.accumBuffer[2]); SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, mAttribs.accumBuffer[3]); SDL_GL_SetAttribute(SDL_GL_STEREO, mAttribs.stereo); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, mAttribs.multisampleBuffers); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, mAttribs.multisampleSamples); SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, mAttribs.swapControl); SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, mAttribs.hardwareOnly); } Video::~Video() { SDL_FreeSurface(mContext); if (gCurrentVideo == this) gCurrentVideo = 0; } void Video::setVideoMode(const int mode[3]) { if (mode != mAttribs.mode || !mContext) { if (mContext) SDL_FreeSurface(mContext); mContext = SDL_SetVideoMode(mode[0], mode[1], mode[2], SDL_OPENGL | mFlags); if (mContext) { mAttribs.mode[0] = mode[0]; mAttribs.mode[1] = mode[1]; mAttribs.mode[2] = mode[2]; #if !defined(linux) && !defined(__linux) && !defined(__linux__) logInfo("video context recreated"); Dispatch::global().dispatch("video.newcontext"); #endif } else Error(Error::SDL_VIDEOMODE).raise(); } } Video::Attributes Video::attributes() const { return mAttribs; } void Video::resize(int width, int height) { int mode[] = {width, height, mAttribs.mode[2]}; setVideoMode(mode); } bool Video::iconify() { return SDL_WM_IconifyWindow(); } void Video::setCaption(const std::string& caption) { mAttribs.caption = caption; SDL_WM_SetCaption(caption.c_str(), 0); } void Video::setIcon() { if (mAttribs.icon != "") { Image icon(mAttribs.icon); icon.setAsIcon(); } } std::string Video::getCaption() const { return mAttribs.caption; } const std::string& Video::getIcon() const { return mAttribs.icon; } void Video::setFull(bool full) { if (full != isFull() || !mContext) { if (mContext) { mFlags ^= SDL_FULLSCREEN; #if defined(linux) || defined(__linux) || defined(__linux__) if (SDL_WM_ToggleFullScreen(mContext) == 0) #endif recreateContext(); } else { if (full) mFlags |= SDL_FULLSCREEN; else mFlags &= ~SDL_FULLSCREEN; } } } void Video::toggleFull() { setFull(!isFull()); } bool Video::isFull() const { return mFlags & SDL_FULLSCREEN; } void Video::setCursorVisible(bool hasCursor) { SDL_ShowCursor(hasCursor? SDL_ENABLE : SDL_DISABLE); } void Video::toggleCursorVisible() { setCursorVisible(!isCursorVisible()); } bool Video::isCursorVisible() const { return (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE); } void Video::setResizable(bool resizable) { if (resizable != isResizable() || !mContext) { if (mContext) { mFlags ^= SDL_RESIZABLE; recreateContext(); } else { if (resizable) mFlags |= SDL_RESIZABLE; else mFlags &= ~SDL_RESIZABLE; } } } void Video::toggleResizable() { setResizable(!isResizable()); } bool Video::isResizable() const { return mFlags & SDL_RESIZABLE; } bool Video::isCursorGrab() const { return (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON); } void Video::toggleCursorGrab() { setCursorGrab(!isCursorGrab()); } void Video::setCursorGrab(bool cursorGrab) { SDL_WM_GrabInput(cursorGrab? SDL_GRAB_ON : SDL_GRAB_OFF); } void Video::swap() { SDL_GL_SwapBuffers(); } int Video::getWidth() const { return mContext->w; } int Video::getHeight() const { return mContext->h; } void Video::makeCurrent() const { gCurrentVideo = 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) colorBuffer[0] = colors[0]; if (colors.size() > 1) colorBuffer[1] = colors[1]; if (colors.size() > 2) colorBuffer[2] = colors[2]; if (colors.size() > 3) colorBuffer[3] = colors[3]; settings.get("framebuffer", frameBuffer); settings.get("doublebuffer", doubleBuffer); settings.get("depthbuffer", depthBuffer); settings.get("stencilbuffer", stencilBuffer); std::vector accum; settings.get("accumbuffers", accum); if (accum.size() > 0) accumBuffer[0] = accum[0]; if (accum.size() > 1) accumBuffer[1] = accum[1]; if (accum.size() > 2) accumBuffer[2] = accum[2]; if (accum.size() > 3) accumBuffer[3] = accum[3]; settings.get("stereo", stereo); settings.get("multiesamplebuffers", multisampleBuffers); settings.get("multiesamplesamples", multisampleSamples); settings.get("swapcontrol", swapControl); settings.get("hardwareonly", hardwareOnly); if (!settings.get("caption", caption)) { caption = "Untitled"; } settings.get("icon", icon); settings.get("fullscreen", fullscreen); settings.get("resizable", resizable); settings.get("showcursor", cursorVisible); settings.get("grab", cursorGrab); std::vector dimensions; settings.get("videomode", dimensions); if (dimensions.size() > 1) { mode[0] = dimensions[0]; mode[1] = dimensions[1]; } else if (fullscreen && Backend::isInitialized()) { SDL_Rect** modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE); if (modes == (SDL_Rect**)0) { Mf::logError("no native video mode"); } else if (modes == (SDL_Rect**)-1) { Mf::logWarning("any resolution allowed; " "choosing default 800x600"); mode[0] = 800; mode[1] = 600; } else { mode[0] = (*modes)->w; mode[1] = (*modes)->h; Mf::logInfo << "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) colorBuffer[0] = 3; colorBuffer[1] = 3; colorBuffer[2] = 2; colorBuffer[3] = 0; frameBuffer = 0; doubleBuffer = true; depthBuffer = 16; stencilBuffer = 0; accumBuffer[0] = 0; accumBuffer[1] = 0; accumBuffer[2] = 0; accumBuffer[3] = 0; stereo = false; multisampleBuffers = 0; multisampleSamples = 0; swapControl = false; hardwareOnly = false; mode[0] = 640; mode[1] = 480; mode[2] = 0; fullscreen = false; resizable = false; cursorVisible = true; cursorGrab = false; } Video* Video::gCurrentVideo = 0; // most recently instantiated instance } // namespace Mf