
00001 /*!@file GUI/SDLdisplay.H Fast full-screen displays using SDL */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2002 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/GUI/SDLdisplay.H $ 00035 // $Id: SDLdisplay.H 11829 2009-10-10 00:01:18Z ilink $ 00036 // 00037 00038 #ifndef GUI_SDLDISPLAY_H_DEFINED 00039 #define GUI_SDLDISPLAY_H_DEFINED 00040 00041 #ifdef HAVE_SDL_SDL_H 00042 00043 #include "Component/ModelComponent.H" 00044 #include "Image/Image.H" 00045 #include "Image/Pixels.H" 00046 #include "Util/Timer.H" // for Timer 00047 #include "Video/VideoFormat.H" 00048 #include "Component/EventLog.H" 00049 00050 #include <list> 00051 #include <SDL/SDL.h> // for SDL_Screen 00052 00053 class VideoFrame; 00054 00055 //! Class fo do various fast graphics displays 00056 /*! This class is to facilitate the display of various graphics 00057 stimuli, with an emphasis on strict real-time operation and in 00058 particular on playing movies at a controlled framerate with 00059 microsecond accuracy. Programs using this class, such as 00060 psycho-movie.C, should run as root if SCHED_FIFO scheduling is 00061 required (and I highly recommend it, as it will make timing 00062 reliable). The class uses the SDL library to do the displays. This 00063 class attempts to lock onto the display's vertical blanking for 00064 reliable timing of movie playing. Note that, as far as I know, SDL 00065 does not provide a way to select a screen refresh rate; instead, you 00066 need to specify the refresh rate in your X config. I used the 00067 modeline calculator at 00068 http://xtiming.sourceforge.net/cgi-bin/xtiming.pl to figure out good 00069 modelines for the refresh rates I wanted. For example: for a 120Hz 00070 640x480 display, I got: 00071 00072 Modeline "640x480@120" 55.43 640 672 880 912 480 487 497 505 00073 00074 which I added to the "Monitor" section of /etc/X11/XF86Config-4, and 00075 I also specified that this mode should be used by giving its name in 00076 the "Screen" section: 00077 00078 Subsection "Display" 00079 Depth 24 00080 Modes "1280x1024" "1280x960" "1152x864" "1024x768" "800x600" "640x480@120" 00081 EndSubsection 00082 00083 Always verify on the OSD info page of your monitor that you are 00084 actually getting the refresh rate you want. 00085 00086 For 640x480 @ 60Hz doublescan, I use: 00087 Modeline "640x480@60d" 48.21 640 672 760 792 480 490 495 505 doublescan 00088 00089 For 800x600 @ 60Hz (for LCD goggles): 00090 ModeLine "800x600@60" 40.0 800 840 968 1056 600 601 605 628 +hsync +vsync 00091 00092 For standard VESA 640x480 @ 60Hz: 00093 Modeline "psycho" 25.2 640 656 752 800 480 490 492 525 -hsync -vsync 00094 */ 00095 00096 class SDLdisplay : public ModelComponent 00097 { 00098 public: 00099 00100 /// Different types of inter-frame delay that can be requested 00101 enum DelayType 00102 { 00103 NO_WAIT, ///< Don't wait at all between frames 00104 NEXT_VSYNC, ///< Wait for the next vertical blanking period 00105 NEXT_FRAMETIME ///< Wait for the next frame time according to itsRefreshDelay 00106 }; 00107 00108 // ###################################################################### 00109 /*! @name Constructors, destructor and initialization */ 00110 //@{ 00111 00112 //! Constructor 00113 SDLdisplay(OptionManager& mgr, 00114 const std::string& descrName = "SDL Display", 00115 const std::string& tagName = "SDLdisplay"); 00116 00117 //! Destructor 00118 virtual ~SDLdisplay(); 00119 00120 //! Link us to an EventLog component 00121 /*! If an EventLog component is registered with us, we will send it 00122 lots of event messages, each time a frame or overlay is displayed, 00123 a key pressed, etc. */ 00124 void setEventLog(nub::soft_ref<EventLog> elog); 00125 00126 //@} 00127 00128 // ###################################################################### 00129 /*! @name General display property functions */ 00130 //@{ 00131 00132 //! Get bytes per pixel 00133 inline int getBytesPerPixel() const; 00134 00135 //! Get display dimensions, in pixels 00136 inline Dims getDims() const; 00137 00138 //! Get display width, in pixels 00139 inline int getWidth() const; 00140 00141 //! Get display height, in pixels 00142 inline int getHeight() const; 00143 00144 //! Show or hide mouse pointer 00145 inline void showCursor(const bool showit); 00146 00147 //@} 00148 00149 // ###################################################################### 00150 /*! @name Pixel-level functions */ 00151 //@{ 00152 00153 //! Get the 32 bit color value corresponding to a given RGB pixel 00154 inline Uint32 getUint32color(const PixRGB<byte>& col) const; 00155 00156 //! Get the RGB color triplet corresponding to a given Uint32 color 00157 inline PixRGB<byte> getRGBcolor(const Uint32 col) const; 00158 00159 //@} 00160 00161 // ###################################################################### 00162 /*! @name Basic display and interaction functions */ 00163 //@{ 00164 00165 //! open a SDL display 00166 void openDisplay(); 00167 00168 //! close a SDL display 00169 void closeDisplay(); 00170 00171 //! Lock the screen, as required before using some functions 00172 inline void lockScreen(); 00173 00174 //! Unlock the (previously locked) screen 00175 inline void unlockScreen(); 00176 00177 //! clear the screen 00178 /*! @param col the background color to use 00179 @param vsync will attempt to sync with vertical blanking if true */ 00180 void clearScreen(const PixRGB<byte> col, const bool vsync = true); 00181 00182 //! clear the video back buffer 00183 void clearBackBuffer(); 00184 00185 //! Return the pixel value at (x, y) 00186 // NOTE: The surface must be locked before calling this! 00187 Uint32 getPixel32(const int x, const int y) const; 00188 00189 //! Set the pixel at (x, y) to the given value 00190 // NOTE: The surface must be locked before calling this! 00191 void putPixel32(const int x, const int y, const Uint32 pixel); 00192 00193 //! show a text message 00194 /*! @param ind ind=0 displays the text in the middle of screen, ind =1 displays the text on top or the screen 00195 and ind = -1 displays the message at the buttom of the display 00196 */ 00197 void displayText(const std::string& msg, const bool vsync, 00198 const PixRGB<byte> txtcol, const PixRGB<byte> bgcol, int ind = 0 ); 00199 00200 //! show a text message in a given place 00201 void displayText(const std::string& msg,Point2D<int> p , 00202 const PixRGB<byte> txtcol, 00203 const PixRGB<byte> bgcol,const bool vsync) ; 00204 00205 //! Wait until start of the next vertical blanking, per our frame rate 00206 /*! The vertical blanking period is when the monitor's electron gun 00207 travels from the bottom of the screen back to the top. This 00208 function updates our itsLastSync data member with current time at 00209 start of vertical blanking pulse. Most display functions have a 00210 'vsync' argument and will call this function to perform the sync, 00211 so you usually never have to call this directly. It is provided 00212 here just in case. If checkdelay is true, we will log a warning if 00213 it has been more than one itsRefreshDelay period since the last 00214 time we were called. No logging is made if quiet is true, 00215 otherwise start and end times are logged. 00216 00217 NOTE that this does not necessarily wait for just the next 00218 hardware vsync; instead we wait for the next hardware vsync that 00219 just precedes our next desired frame according to 00220 itsRefreshDelay. So even though your monitor may run at 60Hz or 00221 120Hz, if itsRefreshDelay is 33333us, your actual displayed frame 00222 rate will only be 30Hz when you use waitNextRequestedVsync(). */ 00223 void waitNextRequestedVsync(const bool checkdelay = false, 00224 const bool quiet = true); 00225 00226 /// Wait for the next frame time, per our frame rate 00227 void waitNextRequestedFrameTime(const int frame, 00228 const bool checkdelay = false, 00229 const bool quiet = true); 00230 00231 //! Wait for a number of frame periods 00232 /*! This just repeatedly calles waitNextRequestedVsync() */ 00233 void waitFrames(const int n); 00234 00235 //! Set a desired refresh delay in microseconds, and a fractional tolerance around that delay 00236 void setDesiredRefreshDelayUsec(float usec, float tol=0.05F); 00237 //@} 00238 00239 // ###################################################################### 00240 /*! @name Keyboard functions */ 00241 //@{ 00242 00243 //! wait for a keypress and return character for key pressed 00244 /*!by default stdin is cleared try waitForKey(false) to keep stdin buffer */ 00245 int waitForKey(bool doWait=true); 00246 00247 //! wait for a mouseclick and return 1 for left button click and 2 for right button click 00248 /*!by default stdin is cleared try waitForMouseClick(false) to keep stdin buffer */ 00249 int waitForMouseClick(bool doWait=true) ; 00250 long getTimerValue() ; 00251 00252 int waitForMouseWheelEvent(bool doWait=true) ; 00253 //! check whether a mouseclick has occurred and return 1 for key left button clicked and 2 for right button clicked 00254 /*! a value of -1 is returned if no mouse click event occured */ 00255 int checkForMouseClick() ; 00256 00257 //! check whether a keypress has occurred and return char for key pressed 00258 /*! a value of -1 is returned if no keypress occured */ 00259 int checkForKey(); 00260 00261 00262 //! store the string of keypresses input by the user until the terminating character has been reached 00263 /*! */ 00264 std::string getString(char terminator); 00265 00266 00267 //@} 00268 00269 // ###################################################################### 00270 /*! @name Image blitting functions */ 00271 //@{ 00272 00273 //! Display an image, centered over the screen area 00274 /*! If you want to display an image that is smaller than the display 00275 area at a well-defined location on the screen, see 00276 displayImagePatch(). This just calls makeBlittableSurface() 00277 followed by displaySurface(). It is often beneficial to use these 00278 other two functions for real-time applications, first preparing 00279 your surfaces when you have some extra available time, and then 00280 getting a faster blit. */ 00281 void displayImage(const Image< PixRGB<byte> >& img, 00282 const bool resiz = false, 00283 const PixRGB<byte> bgcol = PixRGB<byte>(0, 0, 0), 00284 const int frame = -1, const bool vsync = true); 00285 00286 //! Make a blittable surface from an Image 00287 /*! The resulting surface can be displayed using displaySurface(). It 00288 should be freed using SDL_FreeSurface() 00289 @param img the image to be displayed 00290 @param resiz if true, the image will be resized such as to fill-up 00291 at least one dimension of the display (but aspect ratio 00292 will be maintained, and possible borders filled with bgcol) 00293 @param bgcol background color to use around image if image has 00294 different aspect ratio from screen */ 00295 SDL_Surface *makeBlittableSurface(const Image< PixRGB<byte> >& img, 00296 const bool resiz = false, 00297 const PixRGB<byte> bgcol = 00298 PixRGB<byte>(0, 0, 0)); 00299 00300 //! Display an SDL surface that has been pre-formatted for fast blitting 00301 /*! @param img a pre-formatted image; no rescaling will be attempted 00302 and it will just be blitted into the screen. Suitable surfaces 00303 may be obtained by makeBlittableSurface() 00304 @param frame this is just used for the log messages; if it is -1 then 00305 no frame number/duration are logged; if it is -2 both the 00306 start and end of the function execution are logged 00307 @param vsync will attempt to sync with vertical blanking if true */ 00308 void displaySurface(SDL_Surface *img, const int frame = -1, 00309 const bool vsync = true); 00310 00311 00312 //! Display an image patch 00313 /*! @param image an image patch 00314 @param pos the position of the top-left corner of the image 00315 @param frame this is just used for the log messages; if it is -1 then 00316 no frame number/duration are logged; if it is -2 both the 00317 start and end of the function execution are logged 00318 @param vsync will attempt to sync with vertical blanking if true */ 00319 void displayImagePatch(const Image< PixRGB<byte> >& image, 00320 const Point2D<int>& pos, const int frame = -1, 00321 const bool vsync = true, const bool flip = true); 00322 00323 //@} 00324 // ###################################################################### 00325 //! Display an SDLSurface patch on thescreen 00326 /*! @param surf a pointer to a SDL_Surface 00327 @param offset a pointer to a SDL_Rect which encapsulates the offset 00328 @param clip a pointer to a SDL_Rect which encapsulates the clip to be shown from surf 00329 @param frame this is just used for the log messages; if it is -1 then 00330 no frame number/duration are logged; if it is -2 both the 00331 start and end of the function execution are logged 00332 @param vsync will attempt to sync with vertical blanking if true 00333 @param flip will attempt to flip if true 00334 */ 00335 void displaySDLSurfacePatch(SDL_Surface* surf , SDL_Rect* offset , SDL_Rect* clip , const int frame=-2, 00336 const bool vsync = true, const bool flip = true); 00337 00338 // ###################################################################### 00339 /*! @name YUV overlay functions */ 00340 //@{ 00341 00342 //! Check whether somebody has already created a YUV overlay for this display 00343 bool hasYUVoverlay() const; 00344 00345 //! create a YUV overlay of specified size 00346 /*! All the other overlay functions will throw a fatal error if no 00347 overlay has been created. */ 00348 void createYUVoverlay(const Uint32 format, const int w, const int h); 00349 00350 //! create a YUV overlay 00351 /*! All the other overlay functions will throw a fatal error if no 00352 overlay has been created. */ 00353 void createYUVoverlay(const Uint32 format); 00354 00355 //! destroy a previously-created YUV overlay 00356 /*! Overlay displays and normal displays don't mix well in SDL. So, 00357 typically, you would create the overlay just before playing a 00358 movie in YUV mode, then play the movie, then clear the screen and 00359 destroy the overlay, do a few normal displays (like a fixation 00360 cross, some text, etc), and loop. */ 00361 void destroyYUVoverlay(); 00362 00363 //! Lock YUV overlay and get a pointer to it for direct access to pixel data 00364 /*! And what can you do with the pixel data? see psycho-movie.C and 00365 pvisionTCP3-master.C for examples of how to fill it from either 00366 raw MPEG movie frames or from an Image<PixRGB<byte> >. */ 00367 SDL_Overlay* lockYUVoverlay(); 00368 00369 //! Unlock YUV overlay 00370 void unlockYUVoverlay(); 00371 00372 //! display current YUV overlay 00373 void displayYUVoverlay(const int frame, const DelayType dly, const int x, 00374 const int y, const int w, const int h); 00375 00376 //! display current YUV overlay 00377 void displayYUVoverlay(const int frame, const DelayType w); 00378 00379 //! test whether we can do video overlays in the given frame format 00380 bool supportsVideoOverlay(const VideoFormat vidformat) const; 00381 00382 //! create a YUV overlay of specific size from a video format 00383 /*! All the other overlay functions will throw a fatal error if no 00384 overlay has been created. */ 00385 void createVideoOverlay(const VideoFormat vidformat, 00386 const int w, const int h); 00387 00388 //! create a YUV overlay from a video format 00389 /*! All the other overlay functions will throw a fatal error if no 00390 overlay has been created. */ 00391 void createVideoOverlay(const VideoFormat vidformat); 00392 00393 //! copy video data to the current YUV overlay, and display it 00394 void displayVideoOverlay(const VideoFrame& buf, 00395 const int frame, const DelayType w); 00396 00397 //! copy video data to the current YUV overlay, and display it 00398 // at location x, y of the screen and new size rw, rh 00399 void displayVideoOverlay_pos(const VideoFrame& buf, 00400 const int frame, const DelayType w, 00401 const int x, const int y, 00402 const int rw, const int rh); 00403 00404 //! overlay an image onto a video, the copy it to the current YUV overlay, 00405 // displaying it 00406 void displayVideoOverlay_image(const VideoFrame& frame, 00407 const int framenum, 00408 const DelayType dly, 00409 const Image<PixRGB<byte> >& img, 00410 const PixRGB<byte>& transpix, 00411 const uint threads = 1); 00412 00413 //@} 00414 00415 // ###################################################################### 00416 /*! @name Event logging functions */ 00417 //@{ 00418 00419 //! Pass-through to EventLog::pushEvent() 00420 /*! Note that this is a no-op if no EventLog has been registered 00421 with us through a call to setEventLog(). */ 00422 inline void pushEvent(const std::string& msg); 00423 00424 //! Pass-through to EventLog::pushEventBegin() 00425 /*! Note that this is a no-op if no EventLog has been registered 00426 with us through a call to setEventLog(). */ 00427 inline void pushEventBegin(const std::string& msg); 00428 00429 //! Pass-through to EventLog::pushEventEnd() 00430 /*! Note that this is a no-op if no EventLog has been registered 00431 with us through a call to setEventLog(). */ 00432 inline void pushEventEnd(const std::string& msg); 00433 00434 //@} 00435 00436 protected: 00437 OModelParam<Dims> itsDims; //!< screen resolution 00438 OModelParam<int> itsPriority; //!< priority for SCHED_FIFO, or 0 for normal 00439 OModelParam<float> itsRefreshDelay; //!< desired refresh delay in usec 00440 OModelParam<bool> itsFullscreen; //!< whether to run in a fullscreen window 00441 NModelParam<bool> itsSlaveMode; //!< slave mode (someone else opens screen) 00442 00443 void start2(); //!< get started 00444 void stop1(); //!< get stopped 00445 00446 Timer itsTimer; // keep track of time 00447 uint64 itsLastSync; // time of last screen sync 00448 uint64 itsLastOvlDisplay; // time of overlay display 00449 00450 float itsRefreshTolerance;// fraction of refresh delay that we allow before marking frames as SLOW or FAST 00451 00452 // update double-buffering and sync to vertical blanking: 00453 void syncScreen(const bool vsync = true, const bool checkdelay = false, 00454 const bool quiet = false); 00455 00456 // display stuff using SDL: 00457 SDL_Surface *itsScreen; 00458 SDL_Overlay *itsOverlay; 00459 SDL_Overlay *videoOverlay; 00460 00461 private: 00462 // log stuff if desired: 00463 nub::soft_ref<EventLog> itsEventLog; 00464 }; 00465 00466 // ###################################################################### 00467 // ###################################################################### 00468 // #################### Inlined functions #################### 00469 // ###################################################################### 00470 // ###################################################################### 00471 00472 // ###################################################################### 00473 inline Dims SDLdisplay::getDims() const 00474 { return itsDims.getVal(); } 00475 00476 // ###################################################################### 00477 inline int SDLdisplay::getWidth() const 00478 { return itsDims.getVal().w(); } 00479 00480 // ###################################################################### 00481 inline int SDLdisplay::getHeight() const 00482 { return itsDims.getVal().h(); } 00483 00484 // ###################################################################### 00485 inline int SDLdisplay::getBytesPerPixel() const 00486 { return itsScreen->format->BytesPerPixel; } 00487 00488 // ###################################################################### 00489 inline Uint32 SDLdisplay::getUint32color(const PixRGB<byte>& col) const 00490 { return SDL_MapRGB(itsScreen->format, col.red(), col.green(), col.blue()); } 00491 00492 // ###################################################################### 00493 inline PixRGB<byte> SDLdisplay::getRGBcolor(const Uint32 col) const 00494 { LFATAL("unimplemented!"); return PixRGB<byte>(0,0,0); } 00495 00496 // ###################################################################### 00497 inline void SDLdisplay::showCursor(const bool showit) 00498 { 00499 if (showit) SDL_ShowCursor(SDL_ENABLE); 00500 else SDL_ShowCursor(SDL_DISABLE); 00501 } 00502 00503 // ###################################################################### 00504 inline void SDLdisplay::lockScreen() 00505 { 00506 if (SDL_MUSTLOCK(itsScreen)) 00507 { 00508 if (SDL_LockSurface(itsScreen) < 0) 00509 LFATAL("Cannot lock screen: %s", SDL_GetError()); 00510 } 00511 } 00512 // ###################################################################### 00513 inline void SDLdisplay::unlockScreen() 00514 { if (SDL_MUSTLOCK(itsScreen)) SDL_UnlockSurface(itsScreen); } 00515 00516 // ###################################################################### 00517 inline void SDLdisplay::pushEvent(const std::string& msg) 00518 { if (itsEventLog.isValid()) itsEventLog->pushEvent(msg); } 00519 00520 // ###################################################################### 00521 inline void SDLdisplay::pushEventBegin(const std::string& msg) 00522 { if (itsEventLog.isValid()) itsEventLog->pushEventBegin(msg); } 00523 00524 // ###################################################################### 00525 inline void SDLdisplay::pushEventEnd(const std::string& msg) 00526 { if (itsEventLog.isValid()) itsEventLog->pushEventEnd(msg); } 00527 00528 00529 #endif // HAVE_SDL_SDL_H 00530 00531 #endif 00532 00533 // ###################################################################### 00534 /* So things look consistent in everyone's emacs... */ 00535 /* Local Variables: */ 00536 /* indent-tabs-mode: nil */ 00537 /* End: */
1.4.4