psycho-noisecuing.C

Go to the documentation of this file.
00001 /*!@file AppPsycho/psycho-noisecuing.C Psychophysics display for a search for a
00002   target that is presented in various repeated noise backgrounds */
00003 
00004 // //////////////////////////////////////////////////////////////////// //
00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00006 // University of Southern California (USC) and the iLab at USC.         //
00007 // See http://iLab.usc.edu for information about this project.          //
00008 // //////////////////////////////////////////////////////////////////// //
00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00011 // in Visual Environments, and Applications'' by Christof Koch and      //
00012 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00013 // pending; application number 09/912,225 filed July 23, 2001; see      //
00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00015 // //////////////////////////////////////////////////////////////////// //
00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00017 //                                                                      //
00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00019 // redistribute it and/or modify it under the terms of the GNU General  //
00020 // Public License as published by the Free Software Foundation; either  //
00021 // version 2 of the License, or (at your option) any later version.     //
00022 //                                                                      //
00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00026 // PURPOSE.  See the GNU General Public License for more details.       //
00027 //                                                                      //
00028 // You should have received a copy of the GNU General Public License    //
00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00031 // Boston, MA 02111-1307 USA.                                           //
00032 // //////////////////////////////////////////////////////////////////// //
00033 //
00034 // Primary maintainer for this file: Laurent Itti <itti@usc.edu>
00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppPsycho/psycho-searchGabor.C $
00036 // $Id: psycho-searchGabor.C 10794 2009-02-08 06:21:09Z itti $
00037 //
00038 
00039 #include "Component/ModelManager.H"
00040 #include "Image/ColorOps.H" // for makeRGB()
00041 #include "Image/CutPaste.H" // for concatX()
00042 #include "Image/DrawOps.H" // for drawLine()
00043 #include "Image/Image.H"
00044 #include "Image/ShapeOps.H" // for rescale()
00045 #include "Psycho/PsychoDisplay.H"
00046 #include "Psycho/EyeTrackerConfigurator.H"
00047 #include "Psycho/EyeTracker.H"
00048 #include "Psycho/ClassicSearchItem.H"
00049 #include "Psycho/SearchArray.H"
00050 #include "Component/EventLog.H"
00051 #include "Raster/Raster.H"
00052 #include "Util/StringUtil.H"
00053 #include "GUI/GUIOpts.H"
00054 
00055 #include <sstream>
00056 #include <ctime>
00057 #include <vector>
00058 #include <string>
00059 
00060 using namespace std;
00061 
00062 // Trial design for contextual cueing experiments.  May class this up soon. 
00063 // Also may make Trial/Experiment classes as ModelComponents of this style.
00064 // Easier to encapsulate experimental designs as separate from trial content.
00065 
00066 // But for now it's easier to keep everything public.
00067 enum NoiseColor { WHITE, PINK, BROWN };
00068 struct trialAgenda
00069 {
00070   bool repeated; //will the trial have a repeated background?
00071   NoiseColor color;
00072   geom::vec2d targetloc;
00073   uint noiseSeed[3];
00074   Dims scrsize;
00075   trialAgenda(const bool r, const NoiseColor c, 
00076               const geom::vec2d t, Dims d)
00077   {
00078     repeated = r;
00079     color = c;
00080     targetloc = t;
00081     scrsize = d;
00082     randomizeNoise(1); // initialize noise to the same pattern at first
00083   }
00084   trialAgenda() //NULL initializer
00085   { }
00086 
00087   std::string colname() const
00088   {
00089     switch(color) {
00090     case WHITE: return "white";
00091     case PINK:  return "pink";
00092     case BROWN: return "brown";
00093     }
00094     return "";
00095   }
00096 
00097   void randomizeNoise(const uint Nbkgds)
00098   {
00099     for(uint i = 0; i < 3; i++) noiseSeed[i] = randomUpToNotIncluding(Nbkgds)+1;
00100   }
00101 
00102   std::string backgroundFile(const uint comp) const //components are R=0,G=1,B=2
00103   {
00104     //unfortunate hard-coded path
00105     std::string stimdir = "/lab/jshen/projects/eye-cuing/stimuli/noiseseeds";
00106     std::string backFile = sformat("%s/%s%03d.png",stimdir.c_str(),colname().c_str(),noiseSeed[comp]);
00107     
00108     // check if file exists
00109     if(!Raster::fileExists(backFile))
00110       {
00111         // stop all our ModelComponents
00112         //        manager.stop();
00113         LFATAL("Image file %s not found.", backFile.c_str());
00114       }
00115     return backFile;
00116   }
00117 
00118   Image<PixRGB<byte> > generateBkgd() {
00119     return colorizedBkgd();
00120   }
00121   Image<PixRGB<byte> > colorizedBkgd() {
00122     std::vector<Image<byte> > comp;
00123   
00124     for(uint i = 0; i < 3; i++) {
00125       //skips file validation step - dangerous
00126       Image<PixRGB<byte> > tmp = Raster::ReadRGB(backgroundFile(i));
00127       comp.push_back(getPixelComponentImage(tmp,i));
00128     }
00129     Image<PixRGB<byte> > RGBnoise = crop(makeRGB(comp[0],comp[1],comp[2]),Point2D<int>(0,0),scrsize);
00130   
00131     //lower contrast by mixing with gray (64,64,64) or white (128,128,128) 
00132     RGBnoise = RGBnoise/2 + PixRGB<byte>(64,64,64);
00133     return RGBnoise;
00134   }
00135 };
00136 
00137 std::string convertToString(const trialAgenda& val)
00138 {
00139   std::stringstream s; 
00140   s << val.colname() << " noise, ";
00141 
00142   if (val.repeated)
00143     s << "repeated, seed (";
00144   else
00145     s << "random, seed (";
00146   for(uint i = 0; i < 3; i++) 
00147     s << val.noiseSeed[i] << (i<2 ? "," : ")");
00148 
00149   // target is printed with respect to origin at center - translating to origin at upper left
00150   s << ", target @ (" << val.targetloc.x() + val.scrsize.w()/2 << "," << val.targetloc.y() + val.scrsize.h()/2 << ")";
00151   return s.str();
00152 }
00153 
00154 // Utility functions 
00155 
00156 // Generate a random integer uniformly in (x,y);
00157 int randomInRange(const int x, const int y)
00158 {
00159   return randomUpToNotIncluding(y-x-1)+(x+1);
00160 }
00161 
00162 // Generate a random point uniformly in d
00163 geom::vec2d randomPtIn(const Rectangle d)
00164 {
00165   return geom::vec2d(randomInRange(d.left(),d.rightO()),
00166                      randomInRange(d.top(),d.bottomO()));
00167 }
00168 
00169 
00170 
00171 // ######################################################################
00172 static int submain(const int argc, char** argv)
00173 {
00174   MYLOGVERB = LOG_INFO;  // suppress debug messages
00175 
00176   // Instantiate a ModelManager:
00177   ModelManager manager("Psycho Visual Search - cuing");
00178 
00179   nub::soft_ref<EventLog> el(new EventLog(manager));
00180   manager.addSubComponent(el);
00181 
00182   nub::soft_ref<EyeTrackerConfigurator>
00183     etc(new EyeTrackerConfigurator(manager));
00184   manager.addSubComponent(etc);
00185 
00186   nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager));
00187   manager.addSubComponent(d);
00188 
00189   // get post-command-line configs:
00190   if (manager.parseCommandLine(argc, argv, "<Nblocks> <setSize>",2,2) == false)
00191     return(1);
00192 
00193   // hook our various babies up:
00194   nub::soft_ref<EyeTracker> et = etc->getET();
00195   d->setEyeTracker(et);
00196   d->setEventLog(el);
00197   et->setEventLog(el);
00198 
00199   // EyeLink opens the screen for us, so make sure SDLdisplay is slave:
00200   if (etc->getModelParamString("EyeTrackerType").compare("EL") == 0)
00201     d->setModelParamVal("SDLslaveMode", true);
00202 
00203   // let's get all our ModelComponent instances started:
00204   manager.start();
00205   
00206   // pick the left and right response keys
00207   // TODO: allow for arrow keys
00208   char keyleft, keyright;
00209   do {
00210     d->pushEvent("===== key for T pointed left =====");
00211     d->displayText("Press key for response for T pointed left:");
00212     keyleft = d->waitForKey();
00213     d->pushEvent("===== key for T pointed right =====");
00214     d->displayText("Press key for response for T pointed right:");
00215     keyright = d->waitForKey();
00216     if (keyleft == keyright) {
00217       d->displayText(sformat("You must choose two different keys (%d/%d).",keyleft,keyright));
00218       d->waitForKey();
00219     }
00220   }
00221   while (keyleft == keyright);
00222 
00223   // ********************* Initial calibration ********************//
00224   // let's display an ISCAN calibration grid:
00225  
00226   if (etc->getModelParamString("EyeTrackerType").compare("EL") == 0) {
00227         d->pushEventBegin("Calibration");
00228         et->setBackgroundColor(d);
00229         et->calibrate(d);
00230         d->pushEventEnd("Calibration");  
00231   }
00232   else if(etc->getModelParamString("EyeTrackerType").compare("ISCAN") == 0) {
00233     d->clearScreen();
00234     d->displayISCANcalib();
00235     d->waitForKey();
00236 
00237   // let's do an eye tracker calibration:
00238   d->displayText("Press any key to calibrate; other key to skip");
00239   int c = d->waitForKey();
00240   if (c == ' ') d->displayEyeTrackerCalibration(3, 3);
00241   }
00242 
00243   // we are ready to start:
00244   d->clearScreen();
00245   d->displayText("Press any key to start the experiment");
00246   d->waitForKey();
00247 
00248   // **************** Experimental settings *************** //
00249 
00250   // number of images in each block, etc.  
00251   const uint Nrepeats = 6; //repeats per block
00252   const uint Nblocks = fromStr<int>(argv[1]);; //blocks per experiment
00253   const uint Ntrials = 12; //blocks per trial
00254   const uint Nbreak = 5; //blocks per break
00255 
00256   // time out for each trial in seconds
00257   const double Ntimeout = 5.0; 
00258 
00259   // number of available noise frames in the stimuli folder
00260   const uint Nnoises = 256;
00261 
00262   // physical layout of search arrays
00263   const int itemsize = 90;
00264   const int setSize = fromStr<int>(argv[2]); // from cmd line
00265   const double grid_spacing = 120.0, min_spacing = grid_spacing; 
00266   
00267   // size of screen - should be no bigger than 1920x1080
00268   const Dims screenDims = 
00269     fromStr<Dims>(manager.getOptionValString(&OPT_SDLdisplayDims));
00270   
00271   // target/distractor type: we have choice of c o q - t l +
00272   const std::string Ttype = "T", Dtype = "L";
00273   const double phiMax = M_PI*5/8, phiMin = M_PI*3/8; //make the rotation easy to see
00274   
00275   ClassicSearchItemFactory 
00276     targetsLeft(SearchItem::FOREGROUND, Ttype, 
00277                 itemsize,
00278                 Range<double>(-phiMax,-phiMin)),
00279     targetsRight(SearchItem::FOREGROUND, Ttype, 
00280                  itemsize,
00281                  Range<double>(phiMin,phiMax)),
00282     distractors(SearchItem::BACKGROUND, Dtype, 
00283                 itemsize,
00284                 Range<double>(-M_PI/2,M_PI/2));
00285 
00286   // ******************** Trial Design ************************* //
00287   std::vector<rutz::shared_ptr<trialAgenda> > trials;
00288   int tIndex[Ntrials]; 
00289   NoiseColor colors[Ntrials];
00290   bool rep[Ntrials];
00291 
00292   SearchArray sarray(screenDims, grid_spacing, min_spacing, itemsize);
00293   const PixRGB<byte> gray(128,128,128);
00294 
00295   // Design and shuffle trials
00296   initRandomNumbers();
00297   for (uint i = 0; i < Ntrials; i++) 
00298     {
00299       tIndex[i] = i; // for index shuffling
00300       colors[i] = NoiseColor(i%3);
00301       rep[i] = (i < Nrepeats);
00302     }
00303 
00304   for (uint i = 0; i < Ntrials; i++)
00305     {
00306       // a random location for each target
00307       const geom::vec2d pos = randomPtIn(sarray.itemBounds());
00308       
00309       rutz::shared_ptr<trialAgenda> myTrial(new trialAgenda(rep[i],colors[i],pos,screenDims));
00310       myTrial->randomizeNoise(Nnoises); //initialize noise seed
00311       trials.push_back(myTrial);
00312     }
00313   
00314   char buf[256];
00315   //******************* block loop:***********************//
00316   for (uint iblock = 1; iblock <= Nblocks; iblock++) {
00317 
00318     // block design - shuffle blocks
00319     randShuffle(tIndex,Ntrials);   
00320 
00321     d->displayText(sformat("Beginning block %d",iblock));
00322     d->waitForKey();
00323 
00324     sprintf(buf,"===== Beginning block %u/%u =====", iblock,Nblocks);
00325     d->pushEvent(buf);
00326     LINFO("%s",buf);
00327 
00328     rutz::shared_ptr<trialAgenda> thisTrial;    
00329     //******************* trial loop:***********************//
00330     for (uint itrial = 1; itrial <= Ntrials; itrial++) {
00331 
00332       //send trial information to log
00333       sprintf(buf, "===== Block %u/%u, Trial %u/%u =====",
00334               iblock, Nblocks, itrial, Ntrials);
00335       d->pushEvent(buf);
00336       LINFO("%s",buf);
00337 
00338       // pick up the trial depending on this block's sequence
00339       thisTrial = trials[tIndex[itrial-1]];
00340 
00341       // clear display
00342       d->clearScreen();
00343 
00344       // If the background needs randomization, do it here
00345       if(!(thisTrial->repeated)) 
00346         thisTrial->randomizeNoise(Nnoises);  
00347 
00348       // get the background image
00349       Image< PixRGB<byte> > bkgdimg = thisTrial->generateBkgd();   
00350 
00351       // clear the search array of objects
00352       sarray.clear();
00353 
00354       // ******************** generate search array *********************//
00355       // pick target location and orientation, and place
00356       // NB: P is in the center-as-origin coordinate frame
00357       geom::vec2d P = thisTrial->targetloc;
00358       const bool isTargetLeft = (randomDouble() < 0.5);
00359       const std::string tarDir = isTargetLeft ? "left" : "right";
00360       if (isTargetLeft)
00361         sarray.addElement(targetsLeft.make(P));
00362       else
00363         sarray.addElement(targetsRight.make(P));
00364 
00365       // generate the distractors
00366       sarray.generateBackground(distractors, 2, false, 5000, false);
00367       // reduce # of distractors to correct amount
00368       sarray.pareBackground(setSize);
00369       
00370       // generate SDL display
00371       Image< PixRGB<byte> > img = bkgdimg + sarray.getImage() - gray;
00372       SDL_Surface *surf1 = d->makeBlittableSurface(img, true);
00373       
00374       // give a chance to other processes if single-CPU:
00375       usleep(200000);
00376 
00377       // drift calibration if we're on EyeLink
00378       if (etc->getModelParamString("EyeTrackerType").compare("EL") == 0) {
00379         et->recalibrate(d,-1);
00380         // start the eyetracker
00381         d->displayFixation();
00382         usleep(300000); //longer SOA to hopefully avoid crash
00383         et->track(true);
00384         d->displayFixationBlink(-1,-1,2,2); //short blink, 2 v-refreshes
00385       } 
00386       else if(etc->getModelParamString("EyeTrackerType").compare("ISCAN") == 0) {
00387         // display fixation, ready to go whenever the user is ready:
00388         d->displayFixation();
00389         d->waitForKey();
00390         // start the eyetracker 
00391         et->track(true);
00392         d->displayFixationBlink(-1,-1,2,2); //short blink, 2 v-refreshes
00393       }
00394       else { //no input
00395         d->displayFixation();
00396         usleep(100000);
00397         d->displayFixationBlink(-1,-1,2,2); //short blink, 2 v-refreshes
00398       }
00399 
00400       //************************ Display array************************//
00401       sprintf(buf, "===== Showing array: %s, turned %s =====",
00402               toStr(*thisTrial).c_str(), tarDir.c_str());
00403       LINFO("%s",buf);
00404 
00405       // actually push the array onto the screen
00406       d->waitNextRequestedVsync(false, true);
00407       d->pushEvent(buf);
00408       d->displaySurface(surf1, 0, true);
00409 
00410       // get response back for key (NB: doesn't always take key input for ISCAN)
00411       const int resp = d->waitForKeyTimeout(1000*Ntimeout);
00412 
00413       // response processing
00414       if(resp == -1) 
00415         sprintf(buf, "trial timed out");
00416       else if(resp != keyleft && resp != keyright)
00417         sprintf(buf,"trial mistaken - neither key pressed (%c, %c/%c)",resp, keyleft, keyright);
00418       else if((resp==keyleft) == isTargetLeft)
00419         sprintf(buf,"trial correct, correct = %s", tarDir.c_str());
00420       else
00421         sprintf(buf,"trial incorrect, correct = %s", tarDir.c_str());
00422               
00423       // push to both the queue and psych data file
00424       d->pushEvent(buf);
00425       LINFO("%s",buf);
00426       
00427       usleep(50000);
00428       et->track(false);
00429 
00430       // clear screen and free the image from memory
00431       d->clearScreen();
00432       SDL_FreeSurface(surf1); 
00433     } // end trial loop
00434 
00435     //allow for a break after every 5 blocks, then recalibrate    
00436     if (iblock%Nbreak==0 && iblock!=Nblocks) 
00437       {
00438         d->displayText("Please take a break: press any key to continue when ready.");
00439         d->waitForKey();
00440 
00441         if (etc->getModelParamString("EyeTrackerType").compare("EL") == 0) {
00442           d->pushEventBegin("Calibration");
00443           et->setBackgroundColor(d);
00444           et->calibrate(d);
00445           d->pushEventEnd("Calibration");  
00446         }
00447         else if(etc->getModelParamString("EyeTrackerType").compare("ISCAN") == 0) {
00448           d->clearScreen();
00449           d->displayISCANcalib();
00450           d->waitForKey();
00451           
00452           // let's do an eye tracker calibration:
00453           d->displayText("<SPACE> to calibrate; other key to skip");
00454           int c = d->waitForKey();
00455           if (c == ' ') d->displayEyeTrackerCalibration(3, 3);
00456         }
00457       }        
00458   }
00459 
00460   d->clearScreen();
00461   d->displayText("Search trials complete.");
00462   d->waitForKey();
00463 
00464   d->displayText("Which background is more familiar?");
00465   d->waitForKey();
00466 
00467   //************************ Background recall trials************************//
00468   int iRepeat = 0;
00469   for(uint i = 0; i < Ntrials; i++) {
00470     rutz::shared_ptr<trialAgenda> thisTrial = trials[i];
00471     if(!thisTrial->repeated) continue;
00472     iRepeat++;
00473 
00474     // NB: if this doesn't work, construct a new one
00475     trialAgenda randTrial = (*thisTrial); // deep copy? 
00476     Dims halfDims = screenDims/2;
00477 
00478 
00479     // generate two different noise patterns, downscaled by 1/2
00480     Image<PixRGB<byte> > rpt_bkgd = rescale(thisTrial->generateBkgd(),halfDims);
00481     randTrial.randomizeNoise(Nnoises); 
00482     Image<PixRGB<byte> > rand_bkgd = rescale(randTrial.generateBkgd(),halfDims);
00483 
00484     // flip a coin and decide left or right
00485     const bool isRepeatLeft = (randomDouble() < 0.5);
00486     const std::string repeatDir = isRepeatLeft ? "left" : "right";
00487 
00488     Image<PixRGB<byte> > two_bkgd;
00489     if (isRepeatLeft) 
00490       two_bkgd = concatX(rpt_bkgd, rand_bkgd);
00491     else
00492       two_bkgd = concatX(rand_bkgd,rpt_bkgd);
00493     
00494     // draw two pixel thick vertical line
00495     drawLine(two_bkgd, Point2D<int>(halfDims.w()-1, 0), Point2D<int>(halfDims.w()-1, halfDims.h()-1),
00496              PixRGB<byte>(255, 255, 0), 1);
00497     drawLine(two_bkgd, Point2D<int>(halfDims.w(), 0), Point2D<int>(halfDims.w(), halfDims.h()-1),
00498                PixRGB<byte>(255, 255, 0), 1);
00499 
00500     sprintf(buf, "===== Recognition for array: %s, on %s side =====",
00501             toStr(*thisTrial).c_str(), repeatDir.c_str());
00502     LINFO("%s",buf);
00503 
00504     d->displayText(sformat("Recognition trial %d",iRepeat));
00505     d->waitForKey();
00506     SDL_Surface *surf1 = d->makeBlittableSurface(two_bkgd, true);
00507 
00508     // push the two images onto the screen
00509     d->waitNextRequestedVsync(false, true);
00510     d->pushEvent(buf);
00511     d->displaySurface(surf1, 0, true);
00512 
00513     // get response back for key (NB: doesn't always take key input for ISCAN)
00514     const int resp = d->waitForKey();
00515 
00516     // response processing
00517     if(resp != keyleft && resp != keyright)
00518       sprintf(buf,"recognition trial mistaken - neither key pressed (%c, %c/%c)",resp, keyleft, keyright);
00519     else if((resp==keyleft) == isRepeatLeft)
00520       sprintf(buf,"recognition trial correct, correct = %s", repeatDir.c_str());
00521     else
00522       sprintf(buf,"recognition trial incorrect, correct = %s", repeatDir.c_str());
00523               
00524     // push to both the queue and psych data file
00525     d->pushEvent(buf);
00526     LINFO("%s",buf);
00527   }
00528 
00529   //************************ Target recall trials************************//
00530   d->displayText("Where would the target be? Click with the mouse.");
00531   d->waitForMouseClick();
00532 
00533   iRepeat = 0;
00534   for(uint i = 0; i < Ntrials; i++) {
00535     rutz::shared_ptr<trialAgenda> thisTrial = trials[i];
00536     if(!thisTrial->repeated) continue;
00537     iRepeat++;
00538 
00539     Image<PixRGB<byte> > rpt_bkgd = thisTrial->generateBkgd();
00540 
00541 
00542     sprintf(buf, "===== Target retrieval for array: %s =====",
00543             toStr(*thisTrial).c_str());
00544     LINFO("%s",buf);
00545 
00546     d->displayText(sformat("Target retrieval trial %d",iRepeat));
00547     d->waitForMouseClick();
00548     SDL_Surface *surf1 = d->makeBlittableSurface(rpt_bkgd, true);
00549 
00550     // push the two images onto the screen
00551     d->waitNextRequestedVsync(false, true);
00552     d->pushEvent(buf);
00553     d->displaySurface(surf1, 0, true);
00554 
00555     // get response back from mouse 
00556     d->showCursor(true);
00557     SDL_Event event;
00558     while( SDL_WaitEvent( &event )) {     
00559       if(event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT ) {
00560         break;
00561 }       
00562 }       
00563 /*
00564       switch (event.type) {
00565       case SDL_MOUSEMOTION:
00566         printf("Mouse moved by %d,%d to (%d,%d)\n", 
00567                event.motion.xrel, event.motion.yrel,
00568                event.motion.x, event.motion.y);
00569         //break;
00570       case SDL_MOUSEBUTTONDOWN:
00571         printf("Mouse button %d pressed at (%d,%d)\n",
00572                event.button.button, event.button.x, event.button.y);
00573         break;
00574       case SDL_MOUSEBUTTONUP:
00575         printf("Mouse button %d raised at (%d,%d)\n",
00576                event.button.button, event.button.x, event.button.y);
00577         //break;
00578 
00579       }
00580     }*/
00581     d->showCursor(false);
00582 
00583     Point2D<int> resp(event.button.x,event.button.y);
00584     // response processing
00585     sprintf(buf,"target placed at %s",toStr(resp).c_str());
00586               
00587     // push to both the queue and psych data file
00588     d->pushEvent(buf);
00589     LINFO("%s",buf);
00590   }
00591 
00592   d->displayText("Experiment complete. Press any key to exit.  Thank you!");
00593   d->waitForKey();
00594 
00595   // stop all our ModelComponents
00596   manager.stop();
00597 
00598   // all done!
00599   return 0;
00600 }
00601 
00602 // ######################################################################
00603 
00604 extern "C" int main(const int argc, char** argv)
00605 {
00606   // simple wrapper around submain() to catch exceptions (because we
00607   // want to allow PsychoDisplay to shut down cleanly; otherwise if we
00608   // abort while SDL is in fullscreen mode, the X server won't return
00609   // to its original resolution)
00610   try
00611     {
00612       return submain(argc, argv);
00613     }
00614   catch (...)
00615     {
00616       REPORT_CURRENT_EXCEPTION;
00617     }
00618 
00619   return 1;
00620 }
00621 // ######################################################################
00622 /* So things look consistent in everyone's emacs... */
00623 /* Local Variables: */
00624 /* indent-tabs-mode: nil */
00625 /* End: */
Generated on Sun May 8 08:04:12 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3