00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
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
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
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
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
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
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;
00121 int siz2 = (siz - 1) / 2;
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;
00147 int siz2 = (siz - 1) / 2;
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
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
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;
00184
00185
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
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;
00206
00207
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
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
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;
00294 int siz2 = (siz - 1) / 2;
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;
00319 int siz2 = (siz - 1) / 2;
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;
00346 int siz2 = (siz - 1) / 2;
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
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
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
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
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
00445 Uint32 col = getUint32color(color);
00446
00447
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
00458 SDL_Rect screct;screct.w = 640; screct.h = 480;
00459 screct.x = 0; screct.y = 0;
00460
00461
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
00468 SDL_BlitSurface(img, NULL, itsScreen, &screct);
00469
00470 SDL_FillRect(itsScreen, &rect, col);
00471
00472 waitNextRequestedVsync(false, true);
00473 SDL_UpdateRect(itsScreen,screct.x,screct.y,screct.w,screct.h);
00474
00475
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
00487
00488
00489 for(int i=0; i<num_loc-1; i++){
00490
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
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
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
00530 itsEyeTracker->track(true);
00531
00532
00533 for(int i=0; i<num_speed; i++){
00534
00535
00536 displayFixation(location[0][0], location[0][1]);
00537 waitForKey();
00538 clearScreen();
00539
00540
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
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
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
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
00582 SDL_FillRect(itsScreen, &preRect, getGreyUint32());
00583
00584
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
00592 preRect.x = rect.x; preRect.y = rect.y;
00593
00594
00595 pushEvent(sformat("smoothPursuit_squarePosition at (%d, %d)", p.i, p.j));
00596 }
00597
00598
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
00614
00615
00616
00617 for(int i=0; i<num_loc-1; i++){
00618
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
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
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
00657
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
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
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
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
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
00701 clearScreen();
00702 displayFixation();
00703 if(!mouserespond){
00704 waitForKey();
00705 }else{
00706 waitForMouseClick();
00707 }
00708
00709 waitNextRequestedVsync(false, true);
00710
00711
00712 itsEyeTracker->track(true);
00713
00714
00715 displayFixationBlink(-1, -1, 5, 2*timefactor);
00716
00717
00718 pushEventBegin(sformat("eyeTrackerCalibration at (%d, %d)", p.i, p.j));
00719
00720
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);
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);
00733 }
00734 pushEventEnd(sformat("eyeTrackerCalibration at (%d, %d)", p.i, p.j));
00735
00736
00737 itsEyeTracker->track(false);
00738 }
00739
00740
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
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
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
00785
00786 Uint32 color = getUint32color(PixRGB<byte>(r, g, b));
00787
00788
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
00816
00817 Uint32 color = getUint32color(PixRGB<byte>(r, g, b));
00818 Uint32 black = getUint32color(PixRGB<byte>(0, 0, 0));
00819
00820
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
00847 Image<PixRGB<byte> > cimg(itsDims.getVal(), NO_INIT);
00848 cimg.clear(itsBackgroundColor.getVal());
00849
00850
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
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
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
00891
00892
00893
00894 SDL_Rect rect; rect.w = 10; rect.h = 10; rect.x=thePoint.i; rect.y = thePoint.j;
00895
00896
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);
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
00916
00917
00918
00919 SDL_Rect rect; rect.w = 10; rect.h = 10; rect.x=thePoint.i; rect.y = thePoint.j;
00920
00921
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);
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
00963
00964
00965