CDisplay.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. classdef CDisplay < handle
  2. % a display class, manage the most common display functions, such as
  3. % display text, fixation, flip, degree of visual angle. It also stores
  4. % display informations, such as resolution, center x,y, ifi ...
  5. % methods:
  6. % 1. constructor
  7. % obj=CDisplay('monitorSize',size,'viewDistance',viewDistance,'bgColor',bgColor,'Color',color,'fontSize',fz,'skipSync',bSync);
  8. % 2. display text
  9. % dispText(txt[,flip,clearBackground]);
  10. % 3. close screen
  11. % close();
  12. % 4. calculate visual angle (deg) to pixels
  13. % deg2pix(degree)
  14. % 5. display fixation
  15. % dispFixation(size [,type, flip, clearBackground]);
  16. % 6. flip: bring back buffer to front (display)
  17. % flip(obj [, clearBackground])
  18. % Screen class of PTB
  19. % Last modify: 7.7.2011
  20. % Created by: Z. Shi, shi@lmu.de
  21. % 14.07.2011 add createShape function to create simple shapes
  22. % 07.07.2014 add debug option - fullWindow,
  23. properties
  24. wnd = -1; %window handle
  25. bSkipSync = 0;
  26. fullWindow = 1; % full screen
  27. ifi = -1; %inter-frame interval (refresh rate)
  28. cx = -1; % center x
  29. cy = -1; % center y
  30. pdeg; % pixels per degree
  31. bgColor = 0; % background color
  32. color = 255; % front color
  33. fontSize = 14;
  34. lineWidth = 60;
  35. lineSpace = 1.5;
  36. inch = 20;
  37. viewDistance = 57;
  38. nItem = 0;
  39. items;
  40. end
  41. methods
  42. function obj = CDisplay(varargin)
  43. % constructure
  44. % inch,viewDistance, bgColor, color, fontsize
  45. p = inputParser;
  46. p.addParamValue('monitorSize',20,@isnumeric);
  47. p.addParamValue('viewDistance',57,@isnumeric);
  48. p.addParamValue('bgColor',[0 0 0],@isnumeric);
  49. p.addParamValue('Color',[255 255 255],@isnumeric);
  50. p.addParamValue('fontSize',14,@isnumeric);
  51. p.addParamValue('lineWidth',60,@isnumeric);
  52. p.addParamValue('lineSpace',1.5,@isnumeric);
  53. p.addParamValue('skipSync',0,@isnumeric);
  54. p.addParamValue('fullWindow',1,@isnumeric);
  55. p.parse(varargin{:});
  56. %init screens
  57. obj.inch = p.Results.monitorSize;
  58. obj.viewDistance = p.Results.viewDistance;
  59. obj.bgColor = p.Results.bgColor;
  60. obj.color = p.Results.Color;
  61. obj.fontSize = p.Results.fontSize;
  62. obj.lineWidth = p.Results.lineWidth;
  63. obj.lineSpace = p.Results.lineSpace;
  64. obj.bSkipSync = p.Results.skipSync;
  65. obj.fullWindow = p.Results.fullWindow;
  66. try
  67. InitializeMatlabOpenGL;
  68. AssertOpenGL;
  69. priority = MaxPriority('KbCheck');
  70. Priority(priority);
  71. HideCursor;
  72. if obj.bSkipSync
  73. Screen('Preference','SkipSyncTests',1);
  74. else
  75. Screen('Preference','SkipSyncTests',0);
  76. end
  77. screens=Screen('Screens');
  78. screenNumber=max(screens);
  79. if obj.fullWindow
  80. [obj.wnd wsize] = Screen('OpenWindow',screenNumber); % Open On Screen window, mainWnd
  81. else
  82. [obj.wnd wsize] = Screen('OpenWindow',screenNumber,[],[0 0 600 400]);
  83. end
  84. obj.ifi=Screen('GetFlipInterval', obj.wnd);
  85. obj.cx = wsize(3)/2; %center x
  86. obj.cy = wsize(4)/2; %center y
  87. pix = obj.inch*2.54/sqrt(1+9/16)/wsize(3); % calculate one pixel in cm
  88. obj.pdeg = round(2*tan((1/2)*pi/180) * obj.viewDistance / pix);
  89. catch ME
  90. Screen('CloseAll');
  91. Priority(0);
  92. disp(ME.message);
  93. disp('error in initial display');
  94. end
  95. end % end of constructor
  96. function nframes = sec2frames(obj,secs)
  97. %convert seconds to number of frames
  98. nframes = round(secs/obj.ifi);
  99. end
  100. function dispText(obj,txt, flip,clearBackground)
  101. % dispText
  102. try
  103. if nargin < 3
  104. flip = 1;
  105. clearBackground = 1;
  106. end
  107. if nargin == 3
  108. clearBackground = 1;
  109. end
  110. if clearBackground
  111. Screen('FillRect',obj.wnd,obj.bgColor);
  112. end
  113. Screen('TextSize',obj.wnd,obj.fontSize);
  114. DrawFormattedText(obj.wnd,txt,'center','center',obj.color,obj.lineWidth,[],[],obj.lineSpace);
  115. if flip
  116. Screen('Flip', obj.wnd);
  117. end
  118. catch ME
  119. Screen('CloseAll');
  120. Priority(0);
  121. disp(ME.message);
  122. end
  123. end % end of dispText method
  124. function itemIndex = createItem(obj,itemData)
  125. %create items (texture, image, etc.)
  126. itemIndex= Screen('MakeTexture', obj.wnd, itemData);
  127. obj.nItem = obj.nItem + 1;
  128. obj.items(obj.nItem) = itemIndex;
  129. end
  130. function itemIndex = createShape(obj,name,x,y,varargin)
  131. %create simple shape
  132. %be sure to do this before the trial starts
  133. p = inputParser;
  134. p.addRequired('name', @(x) any(strcmpi(x,{'rectangle','circle'})));
  135. p.addRequired('x',@(x) x>0);
  136. p.addRequired('y',@(x) x>0);
  137. p.addParamValue('fill',1,@isnumeric);
  138. p.addParamValue('border',0.1,@(x) x>0);
  139. p.addParamValue('bgColor',obj.bgColor,@isnumeric);
  140. p.addParamValue('color',obj.color,@isnumeric);
  141. p.parse(name,x,y,varargin{:});
  142. xp = round(p.Results.x * obj.pdeg)/2;
  143. yp = round(p.Results.y * obj.pdeg)/2; %convert to pixels
  144. bp = round(p.Results.border * obj.pdeg);
  145. bc = p.Results.bgColor;
  146. fc = p.Results.color;
  147. if length(bc) == 1
  148. bc = repmat(bc,3,1);
  149. end
  150. if length(fc) == 1
  151. fc = repmat(fc,3,1);
  152. end
  153. data = zeros(xp*2,yp*2,3); %store in rgb format
  154. switch p.Results.name
  155. case {'circle'}
  156. if p.Results.fill == 1 %fill
  157. for ix = 1:xp*2
  158. for iy = 1:yp*2
  159. if (ix-xp)*(ix-xp)/xp/xp + (iy-yp)*(iy-yp)/yp/yp < 1
  160. data(ix,iy,:) = fc;
  161. else
  162. data(ix,iy,:) = bc;
  163. end
  164. end
  165. end
  166. else % frame
  167. for ix = 1:xp*2
  168. for iy = 1:yp*2
  169. if (ix-xp)*(ix-xp)/xp/xp + (iy-yp)*(iy-yp)/yp/yp < 1 && ...
  170. (ix-xp)*(ix-xp)/(xp-bp)/(xp-bp) + (iy-yp)*(iy-yp)/(yp-bp)/(yp-bp) >= 1
  171. data(ix,iy,:) = fc;
  172. else
  173. data(ix,iy,:) = bc;
  174. end
  175. end
  176. end
  177. end
  178. case {'rectangle'}
  179. if p.Results.fill == 1 %fill
  180. for ix = 1:xp*2
  181. for iy = 1:yp*2
  182. data(ix,iy,:) = fc;
  183. end
  184. end
  185. else %frame
  186. for ix = 1:xp*2
  187. for iy = 1:yp*2
  188. if abs(ix-xp)>xp-bp || abs(iy-yp)>yp-bp
  189. data(ix,iy,:) = fc;
  190. else
  191. data(ix,iy,:) = bc;
  192. end
  193. end
  194. end
  195. end
  196. end %end of switch
  197. %create texture
  198. itemIndex= Screen('MakeTexture', obj.wnd, data);
  199. obj.nItem = obj.nItem + 1;
  200. obj.items(obj.nItem) = itemIndex;
  201. end
  202. function dispItems(obj, xys, itemIndex, itemSizes,rotations, flip)
  203. %disp items at xys (in visual angle, center 0,0)
  204. if nargin < 6
  205. flip = 1;
  206. end
  207. if nargin < 5
  208. rotations = [];
  209. end
  210. if nargin < 4
  211. itemSizes = [obj.cx / obj.pdeg, obj.cy/obj.pdeg]*2;
  212. end
  213. destRects = zeros(4, length(itemIndex));
  214. for iObj = 1: length(itemIndex)
  215. if size(itemSizes,1) == 1
  216. itemRect = [0 0 itemSizes*obj.pdeg];
  217. else
  218. itemRect = [0 0 itemSizes(iObj,:)*obj.pdeg];
  219. end
  220. rect = CenterRectOnPoint(itemRect,obj.pdeg*xys(iObj,1)+obj.cx, obj.pdeg*xys(iObj,2)+obj.cy);
  221. destRects(:,iObj) = rect';
  222. end
  223. Screen('DrawTextures',obj.wnd,itemIndex,[],destRects,rotations);
  224. if flip
  225. Screen('Flip', obj.wnd);
  226. end
  227. end
  228. function close(obj)
  229. %% dispClose: close display
  230. %close display and delete Screen
  231. Screen('CloseAll');
  232. ShowCursor;
  233. Priority(0);
  234. obj.wnd = -1;
  235. end % end of closeDisp
  236. function pixs=deg2pix(obj, degree)
  237. %% deg2pix: calculate degree to pixels
  238. screenWidth = obj.inch*2.54/sqrt(1+9/16); % calculate screen width in cm
  239. pix=screenWidth/obj.cx/2; %calculates the size of a pixel in cm
  240. pixs = round(2*tan((degree/2)*pi/180) * obj.viewDistance / pix);
  241. end %end of deg2pix
  242. function deg = pix2deg(obj, pixels)
  243. deg = 1/obj.pdeg*pixels;
  244. end
  245. function dispFixation(obj,sz,type,flip,clearBackground)
  246. %% dispCrossFix: display cross fixation
  247. if nargin < 3
  248. type = 1;
  249. flip = 1;
  250. clearBackground = 1;
  251. end
  252. if nargin == 3
  253. flip = 1;
  254. clearBackground = 1;
  255. end
  256. if nargin == 4
  257. clearBackground = 1;
  258. end
  259. if clearBackground
  260. Screen('FillRect',obj.wnd, obj.bgColor);
  261. end
  262. if type == 1
  263. rect = CenterRectOnPoint([0 0 2 sz],obj.cx,obj.cy);
  264. Screen('FillRect',obj.wnd,obj.color,rect);
  265. rect = CenterRectOnPoint([0 0 sz 2],obj.cx,obj.cy);
  266. Screen('FillRect',obj.wnd,obj.color, rect);
  267. else
  268. rect = CenterRectOnPoint([0 0 sz sz],obj.cx,obj.cy);
  269. Screen('FillOval',obj.wnd,obj.color,rect);
  270. end
  271. if flip
  272. Screen('Flip',obj.wnd);
  273. end
  274. end %end of dispCrossFix
  275. function [vbl visonset] = flip(obj,clearBackground, when)
  276. %% flip: put back buffer to screen
  277. if nargin < 3
  278. when = 0;
  279. end
  280. if nargin < 2
  281. clearBackground = 0;
  282. end
  283. if clearBackground
  284. Screen('FillRect',obj.wnd,obj.bgColor);
  285. end
  286. [vbl visonset] = Screen('Flip',obj.wnd, when);
  287. end
  288. end
  289. end