Skip to content

Commit a8ee0e4

Browse files
committed
update vis.checkers, exp.inferParameters
1 parent 8e96027 commit a8ee0e4

File tree

6 files changed

+274
-5
lines changed

6 files changed

+274
-5
lines changed

+exp/inferParameters.m

+18-1
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,20 @@
55
% create some signals just to pass to the definition function and track
66
% which parameter names are used
77

8+
% if ischar(expdef) && file.exists(expdef)
9+
% expdeffun = fileFunction(expdef);
10+
% else
11+
% expdeffun = expdef;
12+
% expdef = which(func2str(expdef));
13+
% end
814
if ischar(expdef) && file.exists(expdef)
915
expdeffun = fileFunction(expdef);
16+
[funcDir, mfile] = fileparts(expdef); addpath(funcDir);
17+
funArgs = nargin(str2func(mfile));
1018
else
1119
expdeffun = expdef;
1220
expdef = which(func2str(expdef));
21+
funArgs = nargin(expdeffun);
1322
end
1423

1524
net = sig.Net;
@@ -24,7 +33,15 @@
2433
e.outputs = net.subscriptableOrigin('outputs');
2534

2635
try
27-
expdeffun(e.t, e.events, e.pars, e.visual, e.inputs , e.outputs, e.audio);
36+
37+
rig = 0;
38+
if funArgs == 7
39+
expdeffun(e.t, e.events, e.pars, e.visual, e.inputs, e.outputs, e.audio);
40+
else
41+
expdeffun(e.t, e.events, e.pars, e.visual, e.inputs, e.outputs, e.audio, rig);
42+
end
43+
44+
% expdeffun(e.t, e.events, e.pars, e.visual, e.inputs , e.outputs, e.audio);
2845
% paramNames will be the strings corresponding to the fields of e.pars
2946
% that the user tried to reference in her expdeffun.
3047
paramNames = e.pars.Subscripts.keys';

+srv/StimulusControl.m

+2-2
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,8 @@ function onWSReceived(obj, ~, eventArgs)
198198
notify(obj, 'ExpStarting', srv.ExpEvent('starting', ref));
199199
case 'completed'
200200
%experiment stopped without any exceptions
201-
ref = data{2}; aborted = data{3};
202-
notify(obj, 'ExpStopped', srv.ExpEvent('completed', ref, aborted));
201+
ref = data{2};
202+
notify(obj, 'ExpStopped', srv.ExpEvent('completed', ref));
203203
case 'expException'
204204
%experiment stopped with an exception
205205
ref = data{2}; err = data{3};

cortexlab/+vis/checker6.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function elem = checker3(t)
1+
function elem = checker6(t)
22
%vis.checker A grid of rectangles
33
% Detailed explanation goes here
44

cortexlab/+vis/checkerLeft.m

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
function elem = checkerLeft(t)
2+
%vis.checker A grid of rectangles
3+
% Detailed explanation goes here
4+
5+
elem = t.Node.Net.subscriptableOrigin('checker');
6+
7+
%% make initial layers to be used as templates
8+
maskTemplate = vis.emptyLayer();
9+
maskTemplate.isPeriodic = false;
10+
maskTemplate.interpolation = 'nearest';
11+
maskTemplate.show = true;
12+
maskTemplate.colourMask = [false false false true];
13+
14+
maskTemplate.textureId = 'checkerMaskPixel';
15+
[maskTemplate.rgba, maskTemplate.rgbaSize] = vis.rgba(0, 0);
16+
maskTemplate.blending = '1-source'; % allows us to lay down our zero alpha value
17+
18+
stencilTemplate = maskTemplate;
19+
stencilTemplate.textureId = 'checkerStencilPixel';
20+
[stencilTemplate.rgba, stencilTemplate.rgbaSize] = vis.rgba(1, 1);
21+
stencilTemplate.blending = 'none';
22+
23+
% pattern layer uses the alpha values laid down by mask layers
24+
patternLayer = vis.emptyLayer();
25+
patternLayer.textureId = sprintf('~checker%i', randi(2^32));
26+
patternLayer.isPeriodic = false;
27+
patternLayer.interpolation = 'nearest';
28+
patternLayer.blending = 'destination'; % use the alpha mask gets laid down before this
29+
30+
%% construct signals used to assemble layers
31+
% N rows by cols signal is derived from the size of the pattern array but
32+
% we skip repeats so that pattern changes don't update the mask layers
33+
% unless the size has acutally changed
34+
nRowsByCols = elem.pattern.flatten().map(@size).skipRepeats();
35+
aziRange = elem.azimuthRange.flatten();
36+
altRange = elem.altitudeRange.flatten();
37+
sizeFrac = elem.rectSizeFrac.flatten();
38+
% signal containing the masking layers
39+
gridMaskLayers = mapn(nRowsByCols, aziRange, altRange, sizeFrac, ...
40+
maskTemplate, stencilTemplate, @gridMask);
41+
% signal contain the checker layer
42+
checkerLayer = scan(elem.pattern.flatten(), @updatePattern,...
43+
elem.colour.flatten(), @updateColour,...
44+
elem.azimuthRange.flatten(), @updateAzi,...
45+
elem.altitudeRange.flatten(), @updateAlt,...
46+
elem.show.flatten(), @updateShow,...
47+
patternLayer); % initial value
48+
%% set default attribute values
49+
elem.layers = [gridMaskLayers checkerLayer];
50+
elem.azimuthRange = [-135 0];
51+
elem.altitudeRange = [-37.5 37.5];
52+
elem.rectSizeFrac = [1 1]; % horizontal and vertical size of each rectangle
53+
elem.pattern = [
54+
1 -1 1 -1
55+
-1 0 0 0
56+
1 0 0 0
57+
-1 1 -1 1];
58+
elem.show = true;
59+
end
60+
61+
%% helper functions
62+
function layer = updatePattern(layer, pattern)
63+
% map pattern from -1 -> 1 range to 0->255, cast to 8 bit integers, then
64+
% convert to RGBA texture format.
65+
[layer.rgba, layer.rgbaSize] = vis.rgbaFromUint8(uint8(127.5*(1 + pattern)), 1);
66+
end
67+
68+
function layer = updateColour(layer, colour)
69+
layer.maxColour = [colour 1];
70+
end
71+
72+
function layer = updateAzi(layer, aziRange)
73+
layer.size(1) = abs(diff(aziRange));
74+
layer.texOffset(1) = mean(aziRange);
75+
end
76+
77+
function layer = updateAlt(layer, altRange)
78+
layer.size(2) = abs(diff(altRange));
79+
layer.texOffset(2) = mean(altRange);
80+
end
81+
82+
function layer = updateShow(layer, show)
83+
layer.show = show;
84+
end
85+
86+
function layers = gridMask(nRowsByCols, aziRange, altRange, sizeFrac, mask, stencil)
87+
gridDims = [abs(diff(aziRange)) abs(diff(altRange))];
88+
cellSize = gridDims./flip(nRowsByCols);
89+
nCols = nRowsByCols(2) + 1;
90+
nRows = nRowsByCols(1) + 1;
91+
midAzi = mean(aziRange);
92+
midAlt = mean(altRange);
93+
%% base layer to imprint area the checker can draw on (by applying an alpha mask)
94+
stencil.texOffset = [midAzi midAlt];
95+
stencil.size = gridDims;
96+
if any(sizeFrac < 1)
97+
%% layers for lines making up mask grid - masks out margins around each square
98+
% make layers for vertical lines
99+
if nCols > 1
100+
azi = linspace(aziRange(1), aziRange(2), nCols);
101+
else
102+
azi = midAzi;
103+
end
104+
collayers = repmat(mask, 1, nCols);
105+
for vi = 1:nCols
106+
collayers(vi).texOffset = [azi(vi) midAlt];
107+
end
108+
[collayers.size] = deal([(1 - sizeFrac(1))*cellSize(1) gridDims(2)]);
109+
% make layers for horizontal lines
110+
if nRows > 1
111+
alt = linspace(altRange(1), altRange(2), nRows);
112+
else
113+
alt = midAlt;
114+
end
115+
rowlayers = repmat(mask, 1, nRows);
116+
for hi = 1:nRows
117+
rowlayers(hi).texOffset = [midAzi alt(hi)];
118+
end
119+
[rowlayers.size] = deal([gridDims(1) (1 - sizeFrac(2))*cellSize(2)]);
120+
%% combine the layers and return
121+
layers = [stencil collayers rowlayers];
122+
else % no mask grid needed as each cell is full size
123+
layers = stencil;
124+
end
125+
126+
end

cortexlab/+vis/checkerRight.m

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
function elem = checkerRight(t)
2+
%vis.checker A grid of rectangles
3+
% Detailed explanation goes here
4+
5+
elem = t.Node.Net.subscriptableOrigin('checker');
6+
7+
%% make initial layers to be used as templates
8+
maskTemplate = vis.emptyLayer();
9+
maskTemplate.isPeriodic = false;
10+
maskTemplate.interpolation = 'nearest';
11+
maskTemplate.show = true;
12+
maskTemplate.colourMask = [false false false true];
13+
14+
maskTemplate.textureId = 'checkerMaskPixel';
15+
[maskTemplate.rgba, maskTemplate.rgbaSize] = vis.rgba(0, 0);
16+
maskTemplate.blending = '1-source'; % allows us to lay down our zero alpha value
17+
18+
stencilTemplate = maskTemplate;
19+
stencilTemplate.textureId = 'checkerStencilPixel';
20+
[stencilTemplate.rgba, stencilTemplate.rgbaSize] = vis.rgba(1, 1);
21+
stencilTemplate.blending = 'none';
22+
23+
% pattern layer uses the alpha values laid down by mask layers
24+
patternLayer = vis.emptyLayer();
25+
patternLayer.textureId = sprintf('~checker%i', randi(2^32));
26+
patternLayer.isPeriodic = false;
27+
patternLayer.interpolation = 'nearest';
28+
patternLayer.blending = 'destination'; % use the alpha mask gets laid down before this
29+
30+
%% construct signals used to assemble layers
31+
% N rows by cols signal is derived from the size of the pattern array but
32+
% we skip repeats so that pattern changes don't update the mask layers
33+
% unless the size has acutally changed
34+
nRowsByCols = elem.pattern.flatten().map(@size).skipRepeats();
35+
aziRange = elem.azimuthRange.flatten();
36+
altRange = elem.altitudeRange.flatten();
37+
sizeFrac = elem.rectSizeFrac.flatten();
38+
% signal containing the masking layers
39+
gridMaskLayers = mapn(nRowsByCols, aziRange, altRange, sizeFrac, ...
40+
maskTemplate, stencilTemplate, @gridMask);
41+
% signal contain the checker layer
42+
checkerLayer = scan(elem.pattern.flatten(), @updatePattern,...
43+
elem.colour.flatten(), @updateColour,...
44+
elem.azimuthRange.flatten(), @updateAzi,...
45+
elem.altitudeRange.flatten(), @updateAlt,...
46+
elem.show.flatten(), @updateShow,...
47+
patternLayer); % initial value
48+
%% set default attribute values
49+
elem.layers = [gridMaskLayers checkerLayer];
50+
elem.azimuthRange = [0 135];
51+
elem.altitudeRange = [-37.5 37.5];
52+
elem.rectSizeFrac = [1 1]; % horizontal and vertical size of each rectangle
53+
elem.pattern = [
54+
1 -1 1 -1
55+
-1 0 0 0
56+
1 0 0 0
57+
-1 1 -1 1];
58+
elem.show = true;
59+
end
60+
61+
%% helper functions
62+
function layer = updatePattern(layer, pattern)
63+
% map pattern from -1 -> 1 range to 0->255, cast to 8 bit integers, then
64+
% convert to RGBA texture format.
65+
[layer.rgba, layer.rgbaSize] = vis.rgbaFromUint8(uint8(127.5*(1 + pattern)), 1);
66+
end
67+
68+
function layer = updateColour(layer, colour)
69+
layer.maxColour = [colour 1];
70+
end
71+
72+
function layer = updateAzi(layer, aziRange)
73+
layer.size(1) = abs(diff(aziRange));
74+
layer.texOffset(1) = mean(aziRange);
75+
end
76+
77+
function layer = updateAlt(layer, altRange)
78+
layer.size(2) = abs(diff(altRange));
79+
layer.texOffset(2) = mean(altRange);
80+
end
81+
82+
function layer = updateShow(layer, show)
83+
layer.show = show;
84+
end
85+
86+
function layers = gridMask(nRowsByCols, aziRange, altRange, sizeFrac, mask, stencil)
87+
gridDims = [abs(diff(aziRange)) abs(diff(altRange))];
88+
cellSize = gridDims./flip(nRowsByCols);
89+
nCols = nRowsByCols(2) + 1;
90+
nRows = nRowsByCols(1) + 1;
91+
midAzi = mean(aziRange);
92+
midAlt = mean(altRange);
93+
%% base layer to imprint area the checker can draw on (by applying an alpha mask)
94+
stencil.texOffset = [midAzi midAlt];
95+
stencil.size = gridDims;
96+
if any(sizeFrac < 1)
97+
%% layers for lines making up mask grid - masks out margins around each square
98+
% make layers for vertical lines
99+
if nCols > 1
100+
azi = linspace(aziRange(1), aziRange(2), nCols);
101+
else
102+
azi = midAzi;
103+
end
104+
collayers = repmat(mask, 1, nCols);
105+
for vi = 1:nCols
106+
collayers(vi).texOffset = [azi(vi) midAlt];
107+
end
108+
[collayers.size] = deal([(1 - sizeFrac(1))*cellSize(1) gridDims(2)]);
109+
% make layers for horizontal lines
110+
if nRows > 1
111+
alt = linspace(altRange(1), altRange(2), nRows);
112+
else
113+
alt = midAlt;
114+
end
115+
rowlayers = repmat(mask, 1, nRows);
116+
for hi = 1:nRows
117+
rowlayers(hi).texOffset = [midAzi alt(hi)];
118+
end
119+
[rowlayers.size] = deal([gridDims(1) (1 - sizeFrac(2))*cellSize(2)]);
120+
%% combine the layers and return
121+
layers = [stencil collayers rowlayers];
122+
else % no mask grid needed as each cell is full size
123+
layers = stencil;
124+
end
125+
126+
end

0 commit comments

Comments
 (0)