video.cpp

Go to the documentation of this file.
00001 /* $Id: video.cpp 26693 2008-05-18 13:54:58Z mordante $ */
00002 /*
00003    Copyright (C) 2003 - 2008 by David White <dave@whitevine.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License version 2
00008    or at your option any later version.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013 */
00014 
00015 /**
00016  *  @file video.cpp
00017  *  Video-testprogram, standalone
00018  */
00019 
00020 #include "global.hpp"
00021 
00022 #include <stdio.h>
00023 #include <iostream>
00024 #include <vector>
00025 
00026 #include "events.hpp"
00027 #include "font.hpp"
00028 #include "image.hpp"
00029 #include "log.hpp"
00030 #include "preferences_display.hpp"
00031 #include "video.hpp"
00032 
00033 #define LOG_DP LOG_STREAM(info, display)
00034 #define ERR_DP LOG_STREAM(err, display)
00035 
00036 #define TEST_VIDEO_ON 0
00037 
00038 #if (TEST_VIDEO_ON==1)
00039 
00040 #include <stdlib.h>
00041 
00042 // Testprogram takes three args: x-res y-res colour-depth
00043 int main( int argc, char** argv )
00044 {
00045     if( argc != 4 ) {
00046         printf( "usage: %s x-res y-res bitperpixel\n", argv[0] );
00047         return 1;
00048     }
00049     SDL_Init(SDL_INIT_VIDEO);
00050     CVideo video;
00051 
00052     printf( "args: %s, %s, %s\n", argv[1], argv[2], argv[3] );
00053 
00054     printf( "(%d,%d,%d)\n", strtoul(argv[1],0,10), strtoul(argv[2],0,10),
00055                             strtoul(argv[3],0,10) );
00056 
00057     if( video.setMode( strtoul(argv[1],0,10), strtoul(argv[2],0,10),
00058                             strtoul(argv[3],0,10), FULL_SCREEN ) ) {
00059         printf( "video mode possible\n" );
00060     } else  printf( "video mode NOT possible\n" );
00061     printf( "%d, %d, %d\n", video.getx(), video.gety(),
00062                             video.getBitsPerPixel() );
00063 
00064     for( int s = 0; s < 50; s++ ) {
00065         video.lock();
00066         for( int i = 0; i < video.getx(); i++ )
00067                 video.setPixel( i, 90, 255, 0, 0 );
00068         if( s%10==0)
00069             printf( "frame %d\n", s );
00070         video.unlock();
00071         video.update( 0, 90, video.getx(), 1 );
00072     }
00073     return 0;
00074 }
00075 
00076 #endif
00077 
00078 namespace {
00079     bool fullScreen = false;
00080     int disallow_resize = 0;
00081 }
00082 void resize_monitor::process(events::pump_info &info) {
00083     if(info.resize_dimensions.first >= min_allowed_width
00084     && info.resize_dimensions.second >= min_allowed_height
00085     && disallow_resize == 0) {
00086         preferences::set_resolution(info.resize_dimensions);
00087     }
00088 }
00089 
00090 resize_lock::resize_lock()
00091 {
00092     ++disallow_resize;
00093 }
00094 
00095 resize_lock::~resize_lock()
00096 {
00097     --disallow_resize;
00098 }
00099 
00100 static unsigned int get_flags(unsigned int flags)
00101 {
00102     // SDL under Windows doesn't seem to like hardware surfaces
00103     // for some reason.
00104 #if !(defined(_WIN32) || defined(__APPLE__) || defined(__AMIGAOS4__))
00105         flags |= SDL_HWSURFACE;
00106 #endif
00107     if((flags&SDL_FULLSCREEN) == 0)
00108         flags |= SDL_RESIZABLE;
00109 
00110     return flags;
00111 }
00112 
00113 namespace {
00114 std::vector<SDL_Rect> update_rects;
00115 bool update_all = false;
00116 }
00117 
00118 static bool rect_contains(const SDL_Rect& a, const SDL_Rect& b) {
00119     return a.x <= b.x && a.y <= b.y && a.x+a.w >= b.x+b.w && a.y+a.h >= b.y+b.h;
00120 }
00121 
00122 static void clear_updates()
00123 {
00124     update_all = false;
00125     update_rects.clear();
00126 }
00127 
00128 namespace {
00129 
00130 surface frameBuffer = NULL;
00131 
00132 }
00133 
00134 bool non_interactive()
00135 {
00136     return SDL_GetVideoSurface() == NULL;
00137 }
00138 
00139 surface display_format_alpha(surface surf)
00140 {
00141     if(SDL_GetVideoSurface() != NULL)
00142         return SDL_DisplayFormatAlpha(surf);
00143     else if(frameBuffer != NULL)
00144         return SDL_ConvertSurface(surf,frameBuffer->format,0);
00145     else
00146         return NULL;
00147 }
00148 
00149 surface get_video_surface()
00150 {
00151     return frameBuffer;
00152 }
00153 
00154 SDL_Rect screen_area()
00155 {
00156     const SDL_Rect res = {0,0,frameBuffer->w,frameBuffer->h};
00157     return res;
00158 }
00159 
00160 void update_rect(size_t x, size_t y, size_t w, size_t h)
00161 {
00162     const SDL_Rect rect = {x,y,w,h};
00163     update_rect(rect);
00164 }
00165 
00166 void update_rect(const SDL_Rect& rect_value)
00167 {
00168     if(update_all)
00169         return;
00170 
00171     SDL_Rect rect = rect_value;
00172 
00173     surface const fb = SDL_GetVideoSurface();
00174     if(fb != NULL) {
00175         if(rect.x < 0) {
00176             if(rect.x*-1 >= int(rect.w))
00177                 return;
00178 
00179             rect.w += rect.x;
00180             rect.x = 0;
00181         }
00182 
00183         if(rect.y < 0) {
00184             if(rect.y*-1 >= int(rect.h))
00185                 return;
00186 
00187             rect.h += rect.y;
00188             rect.y = 0;
00189         }
00190 
00191         if(rect.x + rect.w > fb->w) {
00192             rect.w = fb->w - rect.x;
00193         }
00194 
00195         if(rect.y + rect.h > fb->h) {
00196             rect.h = fb->h - rect.y;
00197         }
00198 
00199         if(rect.x >= fb->w) {
00200             return;
00201         }
00202 
00203         if(rect.y >= fb->h) {
00204             return;
00205         }
00206     }
00207 
00208     for(std::vector<SDL_Rect>::iterator i = update_rects.begin();
00209         i != update_rects.end(); ++i) {
00210         if(rect_contains(*i,rect)) {
00211             return;
00212         }
00213 
00214         if(rect_contains(rect,*i)) {
00215             *i = rect;
00216             for(++i; i != update_rects.end(); ++i) {
00217                 if(rect_contains(rect,*i)) {
00218                     i->w = 0;
00219                 }
00220             }
00221 
00222             return;
00223         }
00224     }
00225 
00226     update_rects.push_back(rect);
00227 }
00228 
00229 void update_whole_screen()
00230 {
00231     update_all = true;
00232 }
00233 CVideo::CVideo() : bpp(0), fake_screen(false), help_string_(0), updatesLocked_(0)
00234 {
00235     const int res = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
00236 
00237     if(res < 0) {
00238         ERR_DP << "Could not initialize SDL: " << SDL_GetError() << "\n";
00239         throw CVideo::error();
00240     }
00241 }
00242 
00243 CVideo::CVideo( int x, int y, int bits_per_pixel, int flags)
00244          : bpp(0), fake_screen(false), help_string_(0), updatesLocked_(0)
00245 {
00246     const int res = SDL_Init( SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
00247     if(res < 0) {
00248         ERR_DP << "Could not initialize SDL: " << SDL_GetError() << "\n";
00249         throw CVideo::error();
00250     }
00251 
00252     const int mode_res = setMode( x, y, bits_per_pixel, flags );
00253     if (mode_res == 0) {
00254         ERR_DP << "Could not set Video Mode\n";
00255         throw CVideo::error();
00256     }
00257 }
00258 
00259 CVideo::~CVideo()
00260 {
00261     LOG_DP << "calling SDL_Quit()\n";
00262     SDL_Quit();
00263     LOG_DP << "called SDL_Quit()\n";
00264 }
00265 
00266 void CVideo::blit_surface(int x, int y, surface surf, SDL_Rect* srcrect, SDL_Rect* clip_rect)
00267 {
00268     const surface target(getSurface());
00269     SDL_Rect dst = {x,y,0,0};
00270 
00271     if(clip_rect != NULL) {
00272         const clip_rect_setter clip_setter(target,*clip_rect);
00273         SDL_BlitSurface(surf,srcrect,target,&dst);
00274     } else {
00275         SDL_BlitSurface(surf,srcrect,target,&dst);
00276     }
00277 }
00278 
00279 void CVideo::make_fake()
00280 {
00281     fake_screen = true;
00282     frameBuffer = SDL_CreateRGBSurface(SDL_SWSURFACE,16,16,24,0xFF0000,0xFF00,0xFF,0);
00283     image::set_pixel_format(frameBuffer->format);
00284 }
00285 
00286 int CVideo::modePossible( int x, int y, int bits_per_pixel, int flags )
00287 {
00288     return SDL_VideoModeOK( x, y, bits_per_pixel, get_flags(flags) );
00289 }
00290 
00291 int CVideo::setMode( int x, int y, int bits_per_pixel, int flags )
00292 {
00293     update_rects.clear();
00294     if (fake_screen) return 0;
00295     mode_changed_ = true;
00296 
00297     flags = get_flags(flags);
00298     const int res = SDL_VideoModeOK( x, y, bits_per_pixel, flags );
00299 
00300     if( res == 0 )
00301         return 0;
00302 
00303     fullScreen = (flags & FULL_SCREEN) != 0;
00304     frameBuffer = SDL_SetVideoMode( x, y, bits_per_pixel, flags );
00305 
00306     if( frameBuffer != NULL ) {
00307         image::set_pixel_format(frameBuffer->format);
00308         return bits_per_pixel;
00309     } else  return 0;
00310 }
00311 
00312 bool CVideo::modeChanged()
00313 {
00314     bool ret = mode_changed_;
00315     mode_changed_ = false;
00316     return ret;
00317 }
00318 
00319 int CVideo::setGamma(float gamma)
00320 {
00321     SDL_SetGamma(gamma, gamma, gamma);
00322 
00323     return 0;
00324 }
00325 
00326 int CVideo::getx() const
00327 {
00328     return frameBuffer->w;
00329 }
00330 
00331 int CVideo::gety() const
00332 {
00333     return frameBuffer->h;
00334 }
00335 
00336 int CVideo::getBitsPerPixel()
00337 {
00338     return frameBuffer->format->BitsPerPixel;
00339 }
00340 
00341 int CVideo::getBytesPerPixel()
00342 {
00343     return frameBuffer->format->BytesPerPixel;
00344 }
00345 
00346 int CVideo::getRedMask()
00347 {
00348     return frameBuffer->format->Rmask;
00349 }
00350 
00351 int CVideo::getGreenMask()
00352 {
00353     return frameBuffer->format->Gmask;
00354 }
00355 
00356 int CVideo::getBlueMask()
00357 {
00358     return frameBuffer->format->Bmask;
00359 }
00360 
00361 void CVideo::flip()
00362 {
00363     if(fake_screen)
00364         return;
00365 
00366     if(update_all) {
00367         ::SDL_Flip(frameBuffer);
00368     } else if(update_rects.empty() == false) {
00369         size_t sum = 0;
00370         for(size_t n = 0; n != update_rects.size(); ++n) {
00371             sum += update_rects[n].w*update_rects[n].h;
00372         }
00373 
00374         const size_t redraw_whole_screen_threshold = 80;
00375         if(sum > ((getx()*gety())*redraw_whole_screen_threshold)/100) {
00376             ::SDL_Flip(frameBuffer);
00377         } else {
00378             SDL_UpdateRects(frameBuffer,update_rects.size(),&update_rects[0]);
00379         }
00380     }
00381 
00382     clear_updates();
00383 }
00384 
00385 void CVideo::lock_updates(bool value)
00386 {
00387     if(value == true)
00388         ++updatesLocked_;
00389     else
00390         --updatesLocked_;
00391 }
00392 
00393 bool CVideo::update_locked() const
00394 {
00395     return updatesLocked_ > 0;
00396 }
00397 
00398 void CVideo::lock()
00399 {
00400     if( SDL_MUSTLOCK(frameBuffer) )
00401         SDL_LockSurface( frameBuffer );
00402 }
00403 
00404 void CVideo::unlock()
00405 {
00406     if( SDL_MUSTLOCK(frameBuffer) )
00407         SDL_UnlockSurface( frameBuffer );
00408 }
00409 
00410 int CVideo::mustLock()
00411 {
00412     return SDL_MUSTLOCK(frameBuffer);
00413 }
00414 
00415 surface CVideo::getSurface( void )
00416 {
00417     return frameBuffer;
00418 }
00419 
00420 bool CVideo::isFullScreen() const { return fullScreen; }
00421 
00422 void CVideo::setBpp( int bpp )
00423 {
00424     this->bpp = bpp;
00425 }
00426 
00427 int CVideo::getBpp( void )
00428 {
00429     return bpp;
00430 }
00431 
00432 int CVideo::set_help_string(const std::string& str)
00433 {
00434     font::remove_floating_label(help_string_);
00435 
00436     const SDL_Color colour = {0x0,0x00,0x00,0x77};
00437 
00438 #ifdef USE_TINY_GUI
00439     int size = font::SIZE_NORMAL;
00440 #else
00441     int size = font::SIZE_LARGE;
00442 #endif
00443 
00444     while(size > 0) {
00445         if(font::line_width(str, size) > getx()) {
00446             size--;
00447         } else {
00448             break;
00449         }
00450     }
00451 
00452 #ifdef USE_TINY_GUI
00453     const int border = 2;
00454 #else
00455     const int border = 5;
00456 #endif
00457 
00458     help_string_ = font::add_floating_label(str,size,font::NORMAL_COLOUR,getx()/2,gety(),0.0,0.0,-1,screen_area(),font::CENTER_ALIGN,&colour,border);
00459     const SDL_Rect& rect = font::get_floating_label_rect(help_string_);
00460     font::move_floating_label(help_string_,0.0,-double(rect.h));
00461     return help_string_;
00462 }
00463 
00464 void CVideo::clear_help_string(int handle)
00465 {
00466     if(handle == help_string_) {
00467         font::remove_floating_label(handle);
00468         help_string_ = 0;
00469     }
00470 }
00471 
00472 void CVideo::clear_all_help_strings()
00473 {
00474     clear_help_string(help_string_);
00475 }

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs