PsychoDisplay.C

Go to the documentation of this file.
00001 /*!@file Psycho/PsychoDisplay.C Display psychophysics stimuli */
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/Psycho/PsychoDisplay.C $
00035 // $Id: PsychoDisplay.C 14376 2011-01-11 02:44:34Z pez $
00036 //
00037 
00038 #ifdef HAVE_SDL_SDL_H
00039 
00040 #include "Psycho/PsychoDisplay.H"
00041 
00042 #include "Component/ModelOptionDef.H"
00043 #include "Component/OptionManager.H"
00044 #include "GUI/SDLdisplay.H"
00045 #include "Image/ColorOps.H"
00046 #include "Image/DrawOps.H"
00047 #include "Psycho/EyeTracker.H"
00048 #include "Psycho/PsychoOpts.H"
00049 #include "Util/sformat.H"
00050 #include <vector>
00051 
00052 // Used by: PsychoDisplay
00053 const ModelOptionDef OPT_PsychoDisplayBackgroundColor =
00054   { MODOPT_ARG(PixRGB<byte>), "PsychoDisplayBackgroundColor", &MOC_PSYCHODISP, OPTEXP_CORE,
00055     "Background grey color for PsychoDisplay",
00056     "psycho-background-color", '\0', "<r,g,b>", "128,128,128" };
00057 
00058 // Used by: PsychoDisplay
00059 const ModelOptionDef OPT_PsychoDisplayTextColor =
00060   { MODOPT_ARG(PixRGB<byte>), "PsychoDisplayTextColor", &MOC_PSYCHODISP, OPTEXP_CORE,
00061     "Foreground text color for PsychoDisplay",
00062     "psycho-text-color", '\0', "<r,g,b>", "0,0,0" };
00063 
00064 // Used by: PsychoDisplay
00065 const ModelOptionDef OPT_PsychoDisplayBlack =
00066   { MODOPT_ARG(PixRGB<byte>), "PsychoDisplayBlack", &MOC_PSYCHODISP, OPTEXP_CORE,
00067     "'Black' color for PsychoDisplay",
00068     "psycho-black", '\0', "<r,g,b>", "0,0,0" };
00069 
00070 // Used by: PsychoDisplay
00071 const ModelOptionDef OPT_PsychoDisplayWhite =
00072   { MODOPT_ARG(PixRGB<byte>), "PsychoDisplayWhite", &MOC_PSYCHODISP, OPTEXP_CORE,
00073     "'White' color for PsychoDisplay",
00074     "psycho-white", '\0', "<r,g,b>", "255,255,255" };
00075 
00076 // Used by: PsychoDisplay
00077 const ModelOptionDef OPT_PsychoDisplayFixationIcon =
00078   { MODOPT_ARG_STRING, "PsychoDisplayFixationIcon", &MOC_PSYCHODISP, OPTEXP_CORE,
00079     "Filename of fixation image icon, instead of displaying fixation cross",
00080     "psycho-fixation-icon", '\0', "<filename.jpg>", "" };
00081 
00082 
00083 // ######################################################################
00084 PsychoDisplay::PsychoDisplay(OptionManager& mgr, const std::string& descrName,
00085                              const std::string& tagName) :
00086   SDLdisplay(mgr, descrName, tagName),
00087   itsBackgroundColor(&OPT_PsychoDisplayBackgroundColor, this),
00088   itsTextColor(&OPT_PsychoDisplayTextColor, this),
00089   itsBlack(&OPT_PsychoDisplayBlack, this),
00090   itsWhite(&OPT_PsychoDisplayWhite, this),
00091   itsFixationIcon(&OPT_PsychoDisplayFixationIcon, this),
00092   itsFixSiz("PsychoDisplayFixSiz", this, 11),
00093   itsFixThick("PsychoDisplayFixThick", this, 1),
00094   itsEyeTracker()
00095 {  }
00096 
00097 // ######################################################################
00098 PsychoDisplay::~PsychoDisplay()
00099 {  }
00100 
00101 // ######################################################################
00102 void PsychoDisplay::setEyeTracker(nub::soft_ref<EyeTracker> e)
00103 { itsEyeTracker = e; }
00104 
00105 // ######################################################################
00106 void PsychoDisplay::setFixationSize(const int size)
00107 {
00108   itsFixSiz.setVal(size);
00109 }
00110 
00111 // ######################################################################
00112 void PsychoDisplay::clearScreen(const bool vsync)
00113 { SDLdisplay::clearScreen(itsBackgroundColor.getVal(), vsync); }
00114 
00115 // ######################################################################
00116 void PsychoDisplay::displayFixationIcon(const Image< PixRGB<byte> >& image,
00117                 const int x, const int y, const bool vsync)
00118 {
00119   const int siz = image.getWidth();
00120   int i, j; // position of center of cross
00121   int siz2 = (siz - 1) / 2; // half cross size
00122   int w = itsDims.getVal().w(), h = itsDims.getVal().h();
00123 
00124   if (x == -1 || y == -1) {
00125     i = itsDims.getVal().w() / 2 - 1;
00126     j = itsDims.getVal().h() / 2 - 1;
00127   } else {
00128     i = x; j = y;
00129     if (i < siz2) i = siz2; else if (i >= w - siz2) i = w - siz2 - 1;
00130     if (j < siz2) j = siz2; else if (j >= h - siz2) j = h - siz2 - 1;
00131   }
00132   pushEventBegin(sformat("displayFixationIcon (%d, %d)", i, j));
00133 
00134   Point2D<int> xy(i-siz2, j-siz2);
00135   displayImagePatch(image, xy, -2, true, true);
00136 
00137   syncScreen(vsync, false, true);
00138   pushEventEnd("displayFixationIcon");
00139 }
00140 
00141 // ######################################################################
00142 void PsychoDisplay::displayFixation(const int x, const int y, const bool vsync)
00143 {
00144   SDL_Rect rect;
00145   const int thick = itsFixThick.getVal(), siz = itsFixSiz.getVal();
00146   int i, j; // position of center of cross
00147   int siz2 = (siz - 1) / 2; // half cross size
00148   int w = itsDims.getVal().w(), h = itsDims.getVal().h();
00149 
00150   if (x == -1 || y == -1) {
00151     i = itsDims.getVal().w() / 2 - 1;
00152     j = itsDims.getVal().h() / 2 - 1;
00153   } else {
00154     i = x; j = y;
00155     if (i < siz2) i = siz2; else if (i >= w - siz2) i = w - siz2 - 1;
00156     if (j < siz2) j = siz2; else if (j >= h - siz2) j = h - siz2 - 1;
00157   }
00158   pushEventBegin(sformat("displayFixation (%d, %d)", i, j));
00159 
00160   // horizontal bar
00161   rect.x = i - siz2;
00162   rect.y = j - thick / 2;
00163   rect.w = siz;
00164   rect.h = thick;
00165   SDL_FillRect(itsScreen, &rect, getBlackUint32());
00166 
00167   // vertical bar
00168   rect.x = i - thick / 2;
00169   rect.y = j - siz2;
00170   rect.w = thick;
00171   rect.h = siz;
00172   SDL_FillRect(itsScreen, &rect, getBlackUint32());
00173 
00174   syncScreen(vsync, false, true);
00175   pushEventEnd("displayFixation");
00176 }
00177 
00178 // ######################################################################
00179 void PsychoDisplay::displayCircle(const int x, const int y, 
00180                                                                                   const int radius,  
00181                                                                                                                                         const PixRGB<byte> color, const bool vsync)
00182 {
00183   int i, j; // position of center of circle
00184 
00185         // center of circle
00186   if (x == -1 || y == -1) {
00187     i = itsDims.getVal().w() / 2 - 1;
00188     j = itsDims.getVal().h() / 2 - 1;
00189   } else {
00190     i = x; j = y;
00191   }
00192 
00193         // draw circle
00194   pushEventBegin(sformat("displayCircle (%d, %d)", i, j));
00195         aacircleRGBA(itsScreen, i, j, radius, color.red(), color.green(), color.blue(), 0XFF);
00196   syncScreen(vsync, false, true);
00197   pushEventEnd(sformat("displayCircle (%d, %d)", i, j));
00198 }
00199 
00200 // ######################################################################
00201 void PsychoDisplay::displayFilledCircle(const int x, const int y, 
00202                                                                                         const int radius,  
00203                                                                                                                                               const PixRGB<byte> color, const bool vsync)
00204 {
00205   int i, j; // position of center of circle
00206 
00207         // center of circle
00208   if (x == -1 || y == -1) {
00209     i = itsDims.getVal().w() / 2 - 1;
00210     j = itsDims.getVal().h() / 2 - 1;
00211   } else {
00212     i = x; j = y;
00213   }
00214 
00215         // draw circle
00216   pushEventBegin(sformat("displayCircle (%d, %d)", i, j));
00217         filledCircleRGBA(itsScreen, i, j, radius, color.red(), color.green(), color.blue(), 0XFF);
00218   syncScreen(vsync, false, true);
00219   pushEventEnd(sformat("displayCircle (%d, %d)", i, j));
00220 }
00221 
00222 // ######################################################################
00223 void PsychoDisplay::displayFilledCircleBlink(const int x, const int y,
00224                                                                                              const int radius,
00225                                                                                                                                                                                  const PixRGB<byte> color,
00226                                              const int iter, const int delay)
00227 {
00228   pushEventBegin("displayFilledCircleBlink");
00229   for (int i = 0; i < iter; i ++)
00230     {
00231                         displayFilledCircle(x, y, radius, color, true);
00232       for (int i = 0; i < delay; ++i) waitNextRequestedVsync(false, true);
00233       displayFilledCircle(x, y, radius, itsBackgroundColor.getVal(), true);
00234       for (int i = 0; i < delay; ++i) waitNextRequestedVsync(false, true);
00235     }
00236   pushEventEnd("displayFilledCircleBlink");
00237 }
00238 
00239 // ######################################################################
00240 void PsychoDisplay::displayFixationIconBlink(const Image< PixRGB<byte> >& image,
00241                                          const int x, const int y,
00242                                          const int iter, const int delay)
00243 {
00244   pushEventBegin("displayFixationBlink");
00245   for (int i = 0; i < iter; i ++)
00246     {
00247       displayFixationIcon(image, x, y, true);
00248       for (int i = 0; i < delay; ++i) waitNextRequestedVsync(false, true);
00249       clearScreen(true);
00250       for (int i = 0; i < delay; ++i) waitNextRequestedVsync(false, true);
00251     }
00252   pushEventEnd("displayFixationBlink");
00253 }
00254 
00255 // ######################################################################
00256 void PsychoDisplay::displayFixationBlink(const int x, const int y,
00257                                          const int iter, const int delay)
00258 {
00259   pushEventBegin("displayFixationBlink");
00260   for (int i = 0; i < iter; i ++)
00261     {
00262       displayFixation(x, y, true);
00263       for (int i = 0; i < delay; ++i) waitNextRequestedVsync(false, true);
00264       clearScreen(true);
00265       for (int i = 0; i < delay; ++i) waitNextRequestedVsync(false, true);
00266     }
00267   pushEventEnd("displayFixationBlink");
00268 }
00269 
00270 // ######################################################################
00271 void PsychoDisplay::displayColorDotFixationBlink(const int x, const int y,
00272                                               const int iter, const int delay,
00273                                               const PixRGB<byte> color)
00274 {
00275   pushEventBegin("displayColorDotFixationBlink");
00276   for (int i = 0; i < iter; i ++)
00277     {
00278       displayColorDotFixation(x, y, color, true);
00279       for (int i = 0; i < delay; ++i) waitNextRequestedVsync(false, true);
00280       //clearScreen(true);
00281       displayColorDotFixation(x, y, itsBackgroundColor.getVal(), true);
00282       for (int i = 0; i < delay; ++i) waitNextRequestedVsync(false, true);
00283     }
00284   pushEventEnd("displayColorDotFixationBlink");
00285 }
00286 
00287 // ######################################################################
00288 void PsychoDisplay::displayColorDotFixation(const int x, const int y,
00289                                             const PixRGB<byte> color, const bool vsync)
00290 {
00291   SDL_Rect rect;
00292   const int siz = itsFixSiz.getVal() / 2;
00293   int i, j; // position of center of cross
00294   int siz2 = (siz - 1) / 2; // half cross size
00295   int w = itsDims.getVal().w(), h = itsDims.getVal().h();
00296 
00297   if (x == -1 || y == -1) {
00298     i = itsDims.getVal().w() / 2 - 1;
00299     j = itsDims.getVal().h() / 2 - 1;
00300   } else {
00301     i = x; j = y;
00302     if (i < siz2) i = siz2; else if (i >= w - siz2) i = w - siz2 - 1;
00303     if (j < siz2) j = siz2; else if (j >= h - siz2) j = h - siz2 - 1;
00304   }
00305 
00306   rect.x = i - siz2; rect.y = j - siz2; rect.w = siz; rect.h = siz;
00307   SDL_FillRect(itsScreen, &rect, getUint32color(color));
00308 
00309   syncScreen(vsync, false, true);
00310 }
00311 
00312 // ######################################################################
00313 void PsychoDisplay::displayRedDotFixation(const int x, const int y,
00314                                           const bool vsync)
00315 {
00316   SDL_Rect rect;
00317   const int siz = itsFixSiz.getVal() / 2;
00318   int i, j; // position of center of cross
00319   int siz2 = (siz - 1) / 2; // half cross size
00320   int w = itsDims.getVal().w(), h = itsDims.getVal().h();
00321 
00322   if (x == -1 || y == -1) {
00323     i = itsDims.getVal().w() / 2 - 1;
00324     j = itsDims.getVal().h() / 2 - 1;
00325   } else {
00326     i = x; j = y;
00327     if (i < siz2) i = siz2; else if (i >= w - siz2) i = w - siz2 - 1;
00328     if (j < siz2) j = siz2; else if (j >= h - siz2) j = h - siz2 - 1;
00329   }
00330   pushEventBegin(sformat("displayRedDotFixation (%d, %d)", i, j));
00331 
00332   rect.x = i - siz2; rect.y = j - siz2; rect.w = siz; rect.h = siz;
00333   SDL_FillRect(itsScreen, &rect, getUint32color(PixRGB<byte>(255, 0, 0)));
00334 
00335   syncScreen(vsync, false, true);
00336   pushEventEnd("displayRedDotFixation");
00337 }
00338 
00339 // ######################################################################
00340 void PsychoDisplay::displayWhiteDotFixation(const int x, const int y,
00341                                             const bool vsync)
00342 {
00343   SDL_Rect rect;
00344   const int siz = itsFixSiz.getVal() / 2;
00345   int i, j; // position of center of cross
00346   int siz2 = (siz - 1) / 2; // half cross size
00347   int w = itsDims.getVal().w(), h = itsDims.getVal().h();
00348 
00349   if (x == -1 || y == -1) {
00350     i = itsDims.getVal().w() / 2 - 1;
00351     j = itsDims.getVal().h() / 2 - 1;
00352   } else {
00353     i = x; j = y;
00354     if (i < siz2) i = siz2; else if (i >= w - siz2) i = w - siz2 - 1;
00355     if (j < siz2) j = siz2; else if (j >= h - siz2) j = h - siz2 - 1;
00356   }
00357   pushEventBegin(sformat("displayWhiteDotFixation (%d, %d)", i, j));
00358 
00359   rect.x = i - siz2; rect.y = j - siz2; rect.w = siz; rect.h = siz;
00360   SDL_FillRect(itsScreen, &rect, getUint32color(PixRGB<byte>(255, 255, 255)));
00361 
00362   syncScreen(vsync, false, true);
00363   pushEventEnd("displayWhiteDotFixation");
00364 }
00365 
00366 // ######################################################################
00367 void PsychoDisplay::displayRedDotFixationBlink(const int x, const int y,
00368                                                const int iter, const int delay)
00369 {
00370   pushEventBegin("displayRedDotFixationBlink");
00371   for (int i = 0; i < iter; i ++)
00372     {
00373       displayRedDotFixation(x, y, true);
00374       for (int i = 0; i < delay; ++i) waitNextRequestedVsync(false, true);
00375       clearScreen(true);
00376       for (int i = 0; i < delay; ++i) waitNextRequestedVsync(false, true);
00377     }
00378   pushEventEnd("displayRedDotFixationBlink");
00379 }
00380 
00381 // ######################################################################
00382 void PsychoDisplay::displayRedDotFixationBlink(Image< PixRGB<byte> > img, const int x, const int y,
00383                                                const int iter, const int delay)
00384 {
00385   //make a copy of our original surface
00386   SDL_Surface *imgs = makeBlittableSurface(img);
00387   SDL_Rect screct;screct.w = 640; screct.h = 480;
00388   pushEventBegin("displayRedDotFixationBlink");
00389   for (int i = 0; i < iter; i ++)
00390     {
00391       displayImage(img);
00392       displayRedDotFixation(x, y, true);
00393       for (int i = 0; i < delay*4; ++i) waitNextRequestedVsync(false, true);
00394       SDL_BlitSurface(imgs, NULL, itsScreen, &screct);
00395       SDL_UpdateRect(itsScreen,screct.x,screct.y,screct.w,screct.h);
00396       for (int i = 0; i < delay*4; ++i) waitNextRequestedVsync(false, true);
00397     }
00398   pushEventEnd("displayRedDotFixationBlink");
00399 }
00400 
00401 // ######################################################################
00402 void PsychoDisplay::displayISCANcalib()
00403 {
00404   pushEventBegin("ISCANcalibration");
00405   int w = itsDims.getVal().w(), h = itsDims.getVal().h();
00406 
00407   // get the coords of the fixation points in a 640x480 image:
00408   const int npts = 5;
00409   int px[npts] = { 320, 100, 540, 100, 540 };
00410   int py[npts] = { 240, 80,  80,  380, 380 };
00411 
00412   // rescale the coords of the fixation points if image size not 640x480:
00413   if (w != 640)
00414     for (int i = 0; i < npts; i ++)
00415       px[i] = int(round(float(px[i]) * float(w) / 640.0f));
00416   if (h != 480)
00417     for (int i = 0; i < npts; i ++)
00418       py[i] = int(round(float(py[i]) * float(h) / 480.0f));
00419 
00420   // let's loop over the points and display them all at once:
00421   SDL_Rect rect; rect.w = 5; rect.h = 5;
00422   SDL_Rect rect2; rect2.w = 3; rect2.h = 3;
00423   for (int i = 0; i < npts; i ++)
00424     {
00425       rect.x = px[i] - 1; rect.y = py[i] - 1; rect2.x = px[i]; rect2.y = py[i];
00426 
00427       SDL_FillRect(itsScreen, &rect, getBlackUint32());
00428       SDL_FillRect(itsScreen, &rect2, getWhiteUint32());
00429     }
00430   syncScreen(true, false);
00431   pushEventEnd("ISCANcalibration");
00432 }
00433 
00434 //#######################################################################
00435 void PsychoDisplay::displayMovingDotBackground(SDL_Surface *img, const int startX, const int startY,
00436                                   const int endX, const int endY, const float speed, const PixRGB<byte> color)
00437 {
00438 
00439  if (itsEyeTracker.isValid() == false)
00440     LFATAL("You need to set an EyeTracker using setEyeTracker() first");
00441 
00442 
00443 
00444  //get color in RGB space
00445  Uint32 col = getUint32color(color);
00446 
00447  // calulate number of frames (the unit of speed is pixels/frame
00448  float frameNum = sqrt(pow(endX-startX,2)+pow(endY-startY,2))/speed;
00449  std::vector<Point2D<int> > pts;
00450  float unitX = (endX-startX)/frameNum, unitY = (endY-startY)/frameNum;
00451  for(int i=0; i<frameNum; i++){
00452     int x = static_cast<int>(startX + i * unitX);
00453     int y = static_cast<int>(startY + i * unitY);
00454     pts.push_back(Point2D<int>(x, y));
00455  }
00456 
00457  //lets create a rectangle for the whole screem
00458  SDL_Rect screct;screct.w = 640; screct.h = 480;
00459  screct.x = 0; screct.y = 0;
00460 
00461  //let's loop over the points and display them
00462   SDL_Rect rect; rect.w = 7; rect.h = 7;
00463   for(unsigned int i=0; i<pts.size(); i++){
00464     Point2D<int> p = pts[i];
00465     rect.x = p.i-3; rect.y = p.j-3;
00466 
00467     //make a copy of our original surface
00468     SDL_BlitSurface(img, NULL, itsScreen, &screct);
00469     //display new square
00470     SDL_FillRect(itsScreen, &rect, col);
00471     //update screen here
00472     waitNextRequestedVsync(false, true);
00473     SDL_UpdateRect(itsScreen,screct.x,screct.y,screct.w,screct.h);
00474 
00475     // log moving square position:
00476     pushEvent(sformat("Dot_Position at (%d, %d)", p.i, p.j));
00477   }
00478 }
00479 
00480 //######################################################################
00481 void PsychoDisplay::displayMovingDotTrain(const Image< PixRGB<byte> >& img, int location[][2], int num_loc,
00482                             float speed[], int stay[], const  PixRGB<byte> color)
00483 {
00484   SDL_Surface *sdlimg = makeBlittableSurface(img);
00485   pushEventBegin("Display Dot Movement Train");
00486   //clearScreen();
00487 
00488   // foreach transition location
00489   for(int i=0; i<num_loc-1; i++){
00490     // stay
00491     pushEventBegin(sformat("Stay at location (%d, %d)", location[i][0], location[i][1]));
00492 
00493     for(int j=0; j<stay[i]; j++) {waitNextRequestedVsync(false, true);}
00494 
00495     pushEventEnd(sformat("Stay at location (%d, %d)", location[i][0], location[i][1]));
00496 
00497     // move
00498     pushEventBegin(sformat("Move from (%d, %d) to (%d, %d) at %f pixel/frame",
00499                     location[i][0], location[i][1], location[i+1][0],
00500                     location[i+1][1], speed[i]));
00501     displayMovingDotBackground(sdlimg,location[i][0], location[i][1],
00502                                  location[i+1][0], location[i+1][1], speed[i],color);
00503     pushEventEnd(sformat("Move from (%d, %d) to (%d, %d) at %f pixel/frame",
00504                     location[i][0], location[i][1], location[i+1][0],
00505                     location[i+1][1], speed[i]));
00506   }
00507 
00508   // stay for the last location
00509   int l = num_loc-1;
00510   pushEventBegin(sformat("Stay at location (%d, %d)", location[l][0], location[l][1]));
00511   for(int j=0; j<stay[l]; j++){ waitNextRequestedVsync(false, true);}
00512   pushEventEnd(sformat("Stay at location (%d, %d)", location[l][0], location[l][1]));
00513   pushEventEnd("Display Dot Movement Train");
00514 
00515 }
00516 
00517 
00518 
00519 
00520 
00521 // ######################################################################
00522 void PsychoDisplay::displaySmoothPursuitGroupCalibration(int location[][2], int num_loc, float speed[], int num_speed)
00523 
00524 {
00525   pushEventBegin("Eye Tracker Calibration by Smooth Pursuit");
00526 
00527   clearScreen();
00528 
00529   // start the eye tracker
00530   itsEyeTracker->track(true);
00531 
00532   // for each speed
00533   for(int i=0; i<num_speed; i++){
00534 
00535   // display a fixation point at the beginning of the path with different speed
00536   displayFixation(location[0][0], location[0][1]);
00537   waitForKey();
00538   clearScreen();
00539 
00540     // for each start/end pair
00541     for(int j=0; j<num_loc-1; j++){
00542       displaySmoothPursuitCalibration(location[j][0], location[j][1],
00543                    location[j+1][0], location[j+1][1], speed[i]);
00544      }
00545   }
00546 
00547   // stop the eye tracker
00548   itsEyeTracker->track(false);
00549 
00550   clearScreen();
00551 
00552   pushEventEnd("Eye Tracker Calibration by Smooth Pursuit");
00553 }
00554 
00555 // ######################################################################
00556 void PsychoDisplay::displaySmoothPursuitCalibration(
00557                 const int startX, const int startY,
00558                 const int endX, const int endY, const float speed, uint color)
00559 {
00560 
00561   if (itsEyeTracker.isValid() == false)
00562     LFATAL("You need to set an EyeTracker using setEyeTracker() first");
00563 
00564   // calulate number of frames (the unit of speed is pixels/frame
00565   float frameNum = sqrt(pow(endX-startX,2)+pow(endY-startY,2))/speed;
00566   std::vector<Point2D<int> > pts;
00567   float unitX = (endX-startX)/frameNum, unitY = (endY-startY)/frameNum;
00568   for(int i=0; i<frameNum; i++){
00569     int x = static_cast<int>(startX + i * unitX);
00570     int y = static_cast<int>(startY + i * unitY);
00571     pts.push_back(Point2D<int>(x, y));
00572   }
00573 
00574   //let's loop over the points and display them
00575   SDL_Rect rect; rect.w = 7; rect.h = 7;
00576   SDL_Rect preRect; preRect.w = rect.w; preRect.h = rect.h; preRect.x = 0; preRect.y = 0;
00577   for(unsigned int i=0; i<pts.size(); i++){
00578     Point2D<int> p = pts[i];
00579     rect.x = p.i-3; rect.y = p.j-3;
00580 
00581     //erase the square displayed in previous frame
00582     SDL_FillRect(itsScreen, &preRect, getGreyUint32());
00583 
00584     //display new square
00585     SDL_FillRect(itsScreen, &rect, color);
00586 
00587     waitNextRequestedVsync(false, true);
00588     SDL_UpdateRect(itsScreen, preRect.x, preRect.y, preRect.w, preRect.h);
00589     SDL_UpdateRect(itsScreen, rect.x, rect.y, rect.w, rect.h);
00590 
00591     // update previous rectangle location to the current one
00592     preRect.x = rect.x; preRect.y = rect.y;
00593 
00594     // log moving square position:
00595     pushEvent(sformat("smoothPursuit_squarePosition at (%d, %d)", p.i, p.j));
00596   }
00597 
00598   // erase the lastest square displayed
00599   SDL_FillRect(itsScreen, &preRect,
00600                getUint32color(itsBackgroundColor.getVal()));
00601 
00602   waitNextRequestedVsync(false, true);
00603   SDL_UpdateRect(itsScreen, preRect.x, preRect.y, preRect.w, preRect.h);
00604 }
00605 
00606 // ######################################################################
00607 void PsychoDisplay::displaySmoothPursuitFancyTrace(int location[][2], int num_loc,
00608                 float speed[], int stay[], uint color)
00609 {
00610   pushEventBegin("Display Fancy Trace for Smooth Pursuit");
00611   clearScreen();
00612 
00613   // start the eye-tracker
00614   //  itsEyeTracker->track(true);
00615 
00616   // foreach transition location
00617   for(int i=0; i<num_loc-1; i++){
00618     // stay
00619     pushEventBegin(sformat("Stay at location (%d, %d)", location[i][0], location[i][1]));
00620     SDL_Rect rect; rect.w = 7; rect.h = 7;
00621     rect.x=location[i][0]-3; rect.y=location[i][1]-3;
00622     SDL_FillRect(itsScreen, &rect, color);
00623     SDL_UpdateRect(itsScreen, rect.x, rect.y, rect.w, rect.h);
00624     for(int j=0; j<stay[i]; j++){
00625       waitNextRequestedVsync(false, true);
00626     }
00627     SDL_FillRect(itsScreen, &rect, getGreyUint32());
00628     SDL_UpdateRect(itsScreen, rect.x, rect.y, rect.w, rect.h);
00629     pushEventEnd(sformat("Stay at location (%d, %d)", location[i][0], location[i][1]));
00630 
00631     // move
00632     pushEventBegin(sformat("Move from (%d, %d) to (%d, %d) at %f pixel/frame",
00633                     location[i][0], location[i][1], location[i+1][0],
00634                     location[i+1][1], speed[i]));
00635     displaySmoothPursuitCalibration(location[i][0], location[i][1],
00636                                  location[i+1][0], location[i+1][1], speed[i],color);
00637     pushEventEnd(sformat("Move from (%d, %d) to (%d, %d) at %f pixel/frame",
00638                     location[i][0], location[i][1], location[i+1][0],
00639                     location[i+1][1], speed[i]));
00640   }
00641 
00642   // stay for the last location
00643   int l = num_loc-1;
00644   pushEventBegin(sformat("Stay at location (%d, %d)", location[l][0], location[l][1]));
00645   SDL_Rect rect; rect.w = 7; rect.h = 7;
00646   rect.x=location[l][0]-3; rect.y=location[l][1]-3;
00647   SDL_FillRect(itsScreen, &rect, color);
00648   SDL_UpdateRect(itsScreen, rect.x, rect.y, rect.w, rect.h);
00649   for(int j=0; j<stay[l]; j++){
00650   waitNextRequestedVsync(false, true);
00651   }
00652   SDL_FillRect(itsScreen, &rect, getGreyUint32());
00653   SDL_UpdateRect(itsScreen, rect.x, rect.y, rect.w, rect.h);
00654   pushEventEnd(sformat("Stay at location (%d, %d)", location[l][0], location[l][1]));
00655 
00656   // stop the eye-tracker
00657   // itsEyeTracker->track(false);
00658   clearScreen();
00659 
00660   pushEventEnd("Display Fancy Trace for Smooth Pursuit");
00661 }
00662 
00663 
00664 
00665 
00666 // ######################################################################
00667 void PsychoDisplay::displayEyeTrackerCalibration(const int nptshoriz,
00668                                                  const int nptsvertic,
00669                                                  const int timefactor,
00670                                                  const bool mouserespond )
00671 {
00672   if (itsEyeTracker.isValid() == false)
00673     LFATAL("You need to set an EyeTracker using setEyeTracker() first");
00674 
00675   pushEventBegin("EyeTrackerCalibration");
00676   int w = itsDims.getVal().w(), h = itsDims.getVal().h();
00677   int deltax = w / (nptshoriz + 1), deltay = h / (nptsvertic + 1);
00678 
00679   // list all the points we want:
00680   std::vector<Point2D<int> > pts;
00681   for (int j = deltay-1; j < h - deltay; j += deltay)
00682     for (int i = deltax-1; i < w - deltax; i += deltax)
00683       pts.push_back(Point2D<int>(i, j));
00684 
00685   // randomize these babies:
00686   for (uint i = 0; i < pts.size(); i ++)
00687     {
00688       uint j = i + randomUpToNotIncluding(pts.size() - i);
00689       Point2D<int> tmp = pts[i]; pts[i] = pts[j]; pts[j] = tmp;
00690     }
00691 
00692   // let's loop over the points and display them:
00693   SDL_Rect rect; rect.w = 3; rect.h = 3;
00694   SDL_Rect rect2; rect2.w = 1; rect2.h = 1;
00695   while (pts.size()) {
00696     // get current point:
00697     Point2D<int> p = pts.back(); pts.pop_back();
00698     rect.x = p.i - 1; rect.y = p.j - 1; rect2.x = p.i; rect2.y = p.j;
00699 
00700     // show fixation and wait for key:
00701     clearScreen();
00702     displayFixation();
00703     if(!mouserespond){
00704             waitForKey();
00705     }else{
00706             waitForMouseClick();
00707     }
00708 
00709     waitNextRequestedVsync(false, true);
00710 
00711     // start the eye tracker:
00712     itsEyeTracker->track(true);
00713 
00714     // blink the fixation:
00715     displayFixationBlink(-1, -1, 5, 2*timefactor);
00716 
00717     // log fixation position:
00718     pushEventBegin(sformat("eyeTrackerCalibration at (%d, %d)", p.i, p.j));
00719 
00720     // let's flash a marker at the desired position:
00721     for (int k = 0; k < 9; k ++) {
00722       SDL_FillRect(itsScreen, &rect, getBlackUint32());
00723       SDL_FillRect(itsScreen, &rect2, getWhiteUint32());
00724       syncScreen(true, false, true);
00725       for (int i = 0; i < 2*timefactor; ++i)
00726         waitNextRequestedVsync(false, true); // sleep a bit
00727 
00728       SDL_FillRect(itsScreen, &rect, getWhiteUint32());
00729       SDL_FillRect(itsScreen, &rect2, getBlackUint32());
00730       syncScreen(true, false, true);
00731       for (int i = 0; i < 2*timefactor; ++i)
00732         waitNextRequestedVsync(false, true); // sleep a bit
00733     }
00734     pushEventEnd(sformat("eyeTrackerCalibration at (%d, %d)", p.i, p.j));
00735 
00736     // stop the eye tracker:
00737     itsEyeTracker->track(false);
00738   }
00739 
00740   // done!
00741   clearScreen();
00742   pushEventEnd("EyeTrackerCalibration");
00743 }
00744 
00745 // ######################################################################
00746 void PsychoDisplay::displayRandomText(const int stringlength, const int fontsize, const bool vsync , int ind )
00747 {
00748         // generating a random string
00749         char random_str[stringlength];
00750         for(int i=0; i<stringlength; i++){
00751                 random_str[i] = 65 + (int)(26 * (rand() / (RAND_MAX + 1.0)));
00752         }
00753         std::string msg (random_str);
00754         LINFO("random text: %s", msg.c_str());
00755 
00756 
00757         // display the string
00758   SDLdisplay::displayText(msg, vsync, itsTextColor.getVal(),
00759                           itsBackgroundColor.getVal(), ind, fontsize );
00760 }
00761 
00762 // ######################################################################
00763 void PsychoDisplay::displayText(const std::string& msg, const bool vsync , int ind, const int fontsize )
00764 {
00765   SDLdisplay::displayText(msg, vsync, itsTextColor.getVal(),
00766                           itsBackgroundColor.getVal(), ind, fontsize );
00767 }
00768 
00769 // ######################################################################
00770 void PsychoDisplay::displayText(const std::string& msg, const Point2D<int>& p , const PixRGB<byte> txtcol ,const PixRGB<byte> bgcol , const bool vsync)
00771 {
00772   SDLdisplay::displayText(msg, p,txtcol ,bgcol,vsync) ;
00773 }
00774 
00775 // ######################################################################
00776 PixRGB<byte> PsychoDisplay::getGrey() const
00777 { return itsBackgroundColor.getVal(); }
00778 
00779 // ######################################################################
00780 void PsychoDisplay::drawCloud(DOT *clouds, const int numDots,
00781                               const Uint8 r, const Uint8 g, const Uint8 b,
00782                               const bool vsync)
00783 {
00784   // Map the color white to this display (R=0xff, G=0xFF, B=0xFF)
00785   // Note:  If the display is palettized, you must set the palette first.
00786   Uint32 color = getUint32color(PixRGB<byte>(r, g, b));
00787 
00788   // Lock the screen for direct access to the pixels
00789   if ( SDL_MUSTLOCK(itsScreen) ) {
00790     if ( SDL_LockSurface(itsScreen) < 0 ) {
00791       LINFO("Can't lock screen: %s", SDL_GetError());
00792       return;
00793     }
00794   }
00795 
00796   for (int j = 0; j < 25; j ++){
00797     for (int i = 0; i < numDots; i++){
00798       DOT* dot = clouds + j * numDots + i;
00799       if (dot != NULL) putPixel32(dot->x, dot->y, color);
00800       }
00801     }
00802 
00803   if ( SDL_MUSTLOCK(itsScreen) )
00804     SDL_UnlockSurface(itsScreen);
00805 
00806   if (vsync) syncScreen(vsync, true, false);
00807 }
00808 
00809 // ######################################################################
00810 void PsychoDisplay::drawClouds(DOT *newClouds, DOT *oldClouds,
00811                                const int numDots,
00812                                const Uint8 r, const Uint8 g, const Uint8 b,
00813                                const bool vsync)
00814 {
00815   // Map the color white to this display (R=0xff, G=0xFF, B=0xFF)
00816   // Note:  If the display is palettized, you must set the palette first.
00817   Uint32 color = getUint32color(PixRGB<byte>(r, g, b));
00818   Uint32 black = getUint32color(PixRGB<byte>(0, 0, 0));
00819 
00820   // Lock the screen for direct access to the pixels
00821   if ( SDL_MUSTLOCK(itsScreen) ) {
00822     if ( SDL_LockSurface(itsScreen) < 0 ) {
00823       LINFO("Can't lock screen: %s", SDL_GetError());
00824       return;
00825     }
00826   }
00827 
00828   for (int j = 0; j < 25; j ++){
00829     for (int i = 0; i < numDots; i++){
00830       DOT* newdot = newClouds + j * numDots + i;
00831       putPixel32(newdot->x, newdot->y, color);
00832       DOT* olddot = oldClouds + j * numDots + i;
00833       putPixel32(olddot->x, olddot->y, black);
00834     }
00835   }
00836   if ( SDL_MUSTLOCK(itsScreen) )
00837     SDL_UnlockSurface(itsScreen);
00838 
00839   if (vsync) syncScreen(vsync, true, false);
00840 }
00841 
00842 // ######################################################################
00843 int PsychoDisplay::displayNumbers(const int targetRow,
00844                                    const int targetCol, const bool vsync)
00845 {
00846   // let's get a white image:
00847   Image<PixRGB<byte> > cimg(itsDims.getVal(), NO_INIT);
00848   cimg.clear(itsBackgroundColor.getVal());
00849 
00850   // randomize the cell indices
00851   int index[25];
00852   for (int i = 0; i < 25; i++)
00853     index[i] = i;
00854   randShuffle (index, 25);
00855 
00856   int targetNum = -1;
00857   // for each random cell, display a number
00858   for (int i = 0; i < 5; i++)
00859     for (int j = 0; j < 5; j++){
00860       int row = index[i*5+j]/5, col = index[i*5+j]%5;
00861       Point2D<int> p; p.i = col * 128 + 64; p.j = row * 96 + 48;
00862       if (p.i < 0) LERROR("Text does not fit on screen!");
00863       char msg[5];
00864       snprintf(msg, sizeof(msg), "%d%d", i+1, j+1);
00865       writeText(cimg, p, msg,
00866                 itsTextColor.getVal(),
00867                 itsBackgroundColor.getVal());
00868       if (row == targetRow && col == targetCol)
00869         targetNum = (i+1)*10 + (j+1);
00870     }
00871   // let's convert it to something we can blit:
00872   SDL_Surface *surf =
00873     SDL_CreateRGBSurfaceFrom(cimg.getArrayPtr(), cimg.getWidth(),
00874                              cimg.getHeight(), 24, 3 * cimg.getWidth(),
00875                              0x0000ff, 0x00ff00, 0xff0000, 0x0);
00876   SDL_Surface *surf2 = SDL_DisplayFormat(surf);
00877   SDL_FreeSurface(surf);
00878   displaySurface(surf2, -1, vsync);
00879   SDL_FreeSurface(surf2);
00880   return targetNum;
00881 }
00882 
00883 
00884 // ######################################################################
00885 int PsychoDisplay::drawPoint(const Point2D<int> thePoint)
00886 {
00887   if (itsEyeTracker.isValid() == false)
00888     LFATAL("You need to set an EyeTracker using setEyeTracker() first");
00889 
00890   //int w = itsDims.getVal().w(), h = itsDims.getVal().h();
00891 
00892 
00893    // let's loop over the points and display them:
00894   SDL_Rect rect; rect.w = 10; rect.h = 10; rect.x=thePoint.i; rect.y = thePoint.j;
00895 
00896     // log fixation position:
00897     pushEventBegin(sformat("eye tracker instantaneous eye position %d, %d", thePoint.i, thePoint.j));
00898 
00899       SDL_FillRect(itsScreen, &rect, getUint32color(PixRGB<byte>(255, 0, 0)));
00900 
00901       syncScreen(true, false, true);
00902       SDL_UpdateRect(itsScreen, rect.x, rect.y, rect.w, rect.h);
00903        waitNextRequestedVsync(false, true); // sleep a bit
00904        return 1;
00905 }
00906 
00907 
00908 //######################################################################
00909 
00910 int PsychoDisplay::drawPointColor(const Point2D<int> thePoint, PixRGB<byte> color)
00911 {
00912   if (itsEyeTracker.isValid() == false)
00913     LFATAL("You need to set an EyeTracker using setEyeTracker() first");
00914 
00915   //int w = itsDims.getVal().w(), h = itsDims.getVal().h();
00916 
00917 
00918    // let's loop over the points and display them:
00919   SDL_Rect rect; rect.w = 10; rect.h = 10; rect.x=thePoint.i; rect.y = thePoint.j;
00920 
00921     // log fixation position:
00922     pushEventBegin(sformat("eye tracker instantaneous eye position %d, %d", thePoint.i, thePoint.j));
00923 
00924       SDL_FillRect(itsScreen, &rect, getUint32color(color));
00925 
00926       syncScreen(true, false, true);
00927       SDL_UpdateRect(itsScreen, rect.x, rect.y, rect.w, rect.h);
00928        waitNextRequestedVsync(false, true); // sleep a bit
00929        return 1;
00930 }
00931 
00932 //#############################################################################
00933 int PsychoDisplay::drawCalibPoint(const Point2D<int> thePoint)
00934 {
00935   SDL_Rect rect; rect.w = 5; rect.h = 5;
00936   SDL_Rect rect2; rect2.w = 3; rect2.h = 3;
00937   rect.x = thePoint.i - 1; rect.y = thePoint.j - 1; rect2.x = thePoint.i; rect2.y = thePoint.j;
00938   SDL_FillRect(itsScreen, &rect, getBlackUint32());
00939   SDL_FillRect(itsScreen, &rect2, getWhiteUint32());
00940   return 1;
00941 }
00942 
00943 // ######################################################################
00944 Uint32 PsychoDisplay::getGreyUint32() const
00945 { return getUint32color(itsBackgroundColor.getVal()); }
00946 
00947 // ######################################################################
00948 Uint32 PsychoDisplay::getBlackUint32() const
00949 { return getUint32color(itsBlack.getVal()); }
00950 
00951 // ######################################################################
00952 Uint32 PsychoDisplay::getWhiteUint32() const
00953 { return getUint32color(PixRGB<byte>(itsWhite.getVal())); }
00954 
00955 // ######################################################################
00956 void PsychoDisplay::changeBackgroundColor(PixRGB<byte> c)
00957 { itsBackgroundColor.setVal(c); }
00958 
00959 #endif // HAVE_SDL_SDL_H
00960 
00961 // ######################################################################
00962 /* So things look consistent in everyone's emacs... */
00963 /* Local Variables: */
00964 /* indent-tabs-mode: nil */
00965 /* End: */
Generated on Sun May 8 08:05:32 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3