3 //Two types of plaid motion
\r
4 //E. H. Adelson and J. A. Movshon (1982).
\r
5 //Phenomenal coherence of moving visual patterns. Nature 300, 523-525
\r
8 //// Include Psychlops Package
\r
11 namespace PsychlopsSilverlightApp
\r
14 public class PsychlopsMain
\r
19 // Struct for component paremeters
\r
22 public double contrast;
\r
23 public double orientation;
\r
24 public double lambda;
\r
29 ///+ Stimulus drawing function
\r
30 //// A function for stimulus drawing (main body)
\r
31 void drawgratingmovie(Image[] img, component c1, component c2, double contrast, int start, int maxframe, double bg_lum, double alpha)
\r
33 double _xp, _xp2, col1, col2;
\r
34 double contrast1, contrast2;
\r
35 double imageheight, imagewidth;
\r
37 contrast1 = contrast*c1.contrast/(c1.contrast+c2.contrast);
\r
38 contrast2 = contrast*c2.contrast/(c1.contrast+c2.contrast);
\r
40 imageheight = img[0].getHeight();
\r
41 imagewidth = img[0].getWidth();
\r
43 for(int frame=start; frame<start+maxframe+1; frame++){
\r
44 //Display.progressbar(frame, maxframe+1);
\r
45 //img[frame].convert(Image::RGBA);
\r
46 for(int i=0; i<imagewidth; i++){
\r
47 for(int j=0; j<imageheight; j++){
\r
48 _xp = Math.sin(c1.orientation)*(i-imagewidth*0.5) + Math.cos(c1.orientation) * (j-imageheight *0.5);
\r
49 _xp2 = Math.sin(c2.orientation)*(i-imagewidth*0.5) + Math.cos(c2.orientation) * (j-imageheight *0.5);
\r
50 col1 = bg_lum*contrast1*Math.sin(2*Math.PI*_xp/c1.lambda + 2*Math.PI*c1.tf*frame/(double)refresh);
\r
51 col2 = bg_lum*contrast2*Math.sin(2*Math.PI*_xp2/c2.lambda + 2*Math.PI*c2.tf*frame/(double)refresh);
\r
52 img[frame].pix(i,j,new Color(col1+col2+bg_lum));
\r
53 img[frame].alpha(i,j,alpha);
\r
56 //img[frame].cache();
\r
60 ///+ Stimulus drawing function
\r
61 //// A function for stimulus drawing (main body)
\r
63 Canvas display = new Canvas(Canvas.window);
\r
65 //// Declare and initialize local variables
\r
66 int rect_size = 150;
\r
67 double rect_lum = 0.5;
\r
68 double bg_lum = 0.2;
\r
69 double duration = 400;
\r
71 double[] lambda = new double[2], contrast = new double[2], tf = new double[2];
\r
72 double center_orientation = 0.0;
\r
73 Image[,] movie = StaticFunctions.NewArray<Image>(2, 120);
\r
74 Image[,] component_movie = StaticFunctions.NewArray<Image>(4, 120);
\r
75 Image envelope = new Image(), envelope_small = new Image();
\r
77 for(int i=0; i<120; i++)
\r
79 movie[0, i].set(rect_size, rect_size);
\r
80 movie[1, i].set(rect_size, rect_size);
\r
81 component_movie[0, i].set(rect_size/2, rect_size/2);
\r
82 component_movie[1, i].set(rect_size/2, rect_size/2);
\r
83 component_movie[2, i].set(rect_size/2, rect_size/2);
\r
84 component_movie[3, i].set(rect_size/2, rect_size/2);
\r
86 envelope.set(rect_size, rect_size);
\r
87 envelope_small.set(rect_size/2, rect_size/2);
\r
89 Letters let1 = new Letters(), let2 = new Letters(), let3 = new Letters();
\r
90 let1.str = "Component1";
\r
91 let2.str = "Component2";
\r
92 let3.str = "Superposition";
\r
93 let1.centering().shift(-rect_size*1.25, -rect_size);
\r
95 let2.centering().shift(rect_size*1.25, -rect_size);
\r
97 let3.centering().shift(0.0, rect_size*0.75);
\r
100 component c1, c2, c0;
\r
101 c0 = new component{ 0.0,0.0,1.0,1.0 }; //dummy for component movie
\r
103 // Prepare Type-I plaid movie
\r
104 center_orientation = 0.0;
\r
105 orientation_offset = Math.PI/6;
\r
106 contrast[0] = 1.0, contrast[1] = 1.0;
\r
107 lambda[0] = 30.0, lambda[1] = 30.0;
\r
108 tf[0] = 1.0; tf[1] = 1.0;
\r
110 c1 = {contrast[0], center_orientation-orientation_offset, lambda[0], tf[0]};
\r
111 c2 = {contrast[1], center_orientation+orientation_offset, lambda[1], tf[1]};
\r
113 drawgratingmovie(movie[0],c1, c2, 0.5, 0, refresh_int, bg_lum, 1.0);
\r
114 drawgratingmovie(component_movie[0],c0, c2, 0.5, 0, refresh_int, bg_lum, 1.0);
\r
115 drawgratingmovie(component_movie[1],c1, c0, 0.5, 0, refresh_int, bg_lum, 1.0);
\r
119 // Prepare Type-II plaid movie
\r
120 center_orientation = -0.0, orientation_offset = Math.PI/12;
\r
121 contrast[0] = 1.0, contrast[1] = 1.0;
\r
122 lambda[0] = 30.0, lambda[1] = 30.0;
\r
123 tf[0] = 1.0; tf[1] = 4.0;
\r
125 c1 = {contrast[0], center_orientation-orientation_offset, lambda[0], tf[0]};
\r
126 c2 = {contrast[1], center_orientation+orientation_offset, lambda[1], tf[1]};
\r
128 drawgratingmovie(movie[1],c1, c2, 0.5, 0, refresh_int, bg_lum, 1.0);
\r
129 drawgratingmovie(component_movie[2],c0, c2, 0.5, 0, refresh_int, bg_lum, 1.0);
\r
130 drawgratingmovie(component_movie[3],c1, c0, 0.5, 0, refresh_int, bg_lum, 1.0);
\r
134 //draw Gaussian envelopes
\r
135 envelope.clear(new Color(bg_lum)); //clear offscreen image
\r
137 for(int i=0; i<rect_size; i++){
\r
138 _x=i-0.5*rect_size;
\r
139 for(int j=0; j<rect_size; j++){
\r
140 _y=j-0.5*rect_size;
\r
141 envelope.alpha(i,j,1.0-Math.exp(-((_x*_x+_y*_y)/ (2.0*pow(rect_size/6.0, 2.0) ))));
\r
145 envelope_small.clear(new Color(bg_lum)); //clear offscreen image
\r
146 for(int i=0; i<rect_size*0.5; i++){
\r
147 _x=i-0.25*rect_size;
\r
148 for(int j=0; j<rect_size*0.5; j++){
\r
149 _y=j-0.25*rect_size;
\r
150 envelope_small.alpha(i,j,1.0-Math.exp(-((_x*_x+_y*_y)/ (2.0*pow(rect_size/12.0, 2.0) ))));
\r
153 envelope.cache(); //send offscreen image from main memory to GPU
\r
154 envelope_small.cache(); //send offscreen image from main memory to GPU
\r
157 ///+ user interface
\r
158 // Draw user interface
\r
159 Widgets::SelectBox stimulus_type;
\r
160 stimulus_type.area.set(120, 20);
\r
161 stimulus_type.append(L"TypeI");
\r
162 stimulus_type.append(L"TypeII");
\r
163 stimulus_type.centering().shift(-120.0,250.0);
\r
165 Psychlops::Widgets::SelectBox stimulus_type2;
\r
166 stimulus_type2.area.set(120, 20);
\r
167 stimulus_type2.append(L"Continuous");
\r
168 stimulus_type2.append(L"Periodic");
\r
169 stimulus_type2.centering().shift(120.0,250.0);
\r
171 Psychlops::Widgets::Slider duration_slider;
\r
172 duration_slider.area.set(100,20);
\r
173 duration_slider.centering().shift(120,280.0);
\r
174 Interval rng = new Interval();
\r
175 duration_slider.link(duration, 50<=rng<=950, 50.0, 50.0);
\r
176 ///- user interface
\r
181 int period = refresh_int;
\r
183 while(!Keyboard.esc.pushed()) {
\r
184 Display.clear(new Color(bg_lum));
\r
185 movienum = stimulus_type.getSelected(); //if "Type-I" is selected, 0, else frame refresh per sec
\r
188 else period = refresh_int;
\r
191 movie[movienum, frame].centering().draw();
\r
192 envelope.centering().draw();
\r
193 component_movie[movienum*2, frame].centering().shift(-rect_size*0.5, -rect_size).draw();
\r
194 envelope_small.centering().shift(-rect_size*0.5, -rect_size).draw();
\r
195 component_movie[movienum*2+1, frame].centering().shift(rect_size*0.5, -rect_size).draw();
\r
196 envelope_small.centering().shift(rect_size*0.5, -rect_size).draw();
\r
199 ///+ draw user interface
\r
203 stimulus_type.draw();
\r
204 stimulus_type2.draw();
\r
205 if(stimulus_type2.getSelected())duration_slider.draw();
\r
206 ///- draw user interface
\r
208 if(frame++ >= period) frame -= refresh_int;
\r
213 ///- Stimulus drawing function
\r
215 ///+ Main function for demo circumstances
\r
216 public void psychlops_main() {
\r
217 ///+ Demo circumstances
\r
218 //// Spells for run demonstration circumstances
\r
219 Procedure p = new Procedure();
\r
220 //p.setDesign(Procedure::DEMO); //Designate that this is a demo.
\r
221 p.setProcedure(drawplaid); //The argument name is a name of drawing function.
\r
223 ///- Demo circumstances
\r
232 //Position Bias Program
\r
233 namespace PsychlopsSilverlightApp
\r
236 public class PsychlopsMain
\r
239 Image img, img2, img3;
\r
242 Psychlops.Widgets.Slider tfreq;
\r
243 Psychlops.Widgets.Slider contrast;
\r
244 Psychlops.Widgets.Slider lambda;
\r
248 public void psychlops_main()
\r
250 cnvs = new Canvas(300, 600);
\r
251 Interval rng = new Interval();
\r
252 tfreq = new Psychlops.Widgets.Slider("Temporal Frequency(Hz)", -5 <= rng <= 5, 3.0);
\r
253 contrast = new Psychlops.Widgets.Slider("Contrast", 0.0 <= rng <= 1.0, 0.25);
\r
254 lambda = new Psychlops.Widgets.Slider("Wave Length", 10.0 <= rng <= 120.0, 30);
\r
256 img = new Image(isize * 2, isize * 2);
\r
257 img2 = new Image(isize * 2, isize * 2);
\r
258 img3 = new Image(isize * 2, isize * 2);
\r
260 var gabor1 = StaticFunctions.NewArray<Figures.ShaderGabor>(100);
\r
261 foreach(var g in gabor1)
\r
263 g.setSigma(isize / 8).centering().shift(Math.random(300) - 150, Math.random(600) - 300);
\r
264 g.orientation = Math.random(2*Math.PI);
\r
269 cnvs.clear(new Color(0.5));
\r
271 Figures.drawGabor(ref img, isize / 8, 1/lambda, contrast, 0.5 * Math.PI, (double)frames * 2.0 * Math.PI * tfreq / 60);
\r
272 Figures.drawGabor(ref img2, isize / 8, 1 / lambda, contrast, 0.5 * Math.PI, (double)frames * 2.0 * Math.PI * -tfreq / 60);
\r
273 Figures.drawGabor(ref img3, isize / 8, 1 / lambda, contrast, 0.5 * Math.PI, (double)frames * 2.0 * Math.PI * tfreq / 60);
\r
276 //img.centering().shift(0, -isize * 1.5).draw();
\r
277 //img2.centering().draw();
\r
278 //img3.centering().shift(0, isize * 1.5).draw();
\r
281 foreach (var g in gabor1)
\r
283 g.wavelength = lambda;
\r
284 g.phase = (double)frames * 2.0 * Math.PI * tfreq / 60;
\r
285 g.contrast = contrast;
\r
289 if (!Mouse.left.pressed()) frames++;
\r