% TenBitClutTest.m
%
% OBSOLETE - Use ScreenTest, LoadClutTest, or ClutTest.
% 
% Try to figure out the bit-depth of the DAC (and clut) of a video card.
% Note that the number of DAC bits has nothing to do with the pixelSize;
% all Mac and Win videocards that we know of support 8- and 32-bit
% pixelSize. Some support other pixelSizes as well (1, 2, 4, or 16 bits)
% but they aren't as useful as 8 and 32. Most video cards have 8-bit DACs.
% A few (Radius Thunder, ATI Radeon) have 10-bit DACs. And there are some old
% (Radius Thunder) 9-bit-DAC cards out there.
% 
% Options:
% 
% If CHECK_TABLES is set, then various gamma tables are written to, and one
% should at least be able to check that all 10-bits are read.
% 
% CHECK_SQUARE ???
% 
% If MEASURE_SQUARE is set and you have a PR-650 attached to the modem port, you
% can use it measure the effect of twiddling the least significant bit. 
% You could go into this section and modify it for another instrument or
% visual tests.
% 
% Originally supplied to dhb by Jack Nachmias.
% 
% See also SetClut and ScreenDacBits.

% 10/16/98  dhb  Modified original version.
% 10/30/98  dhb  Added three-D gamma test, based on email
%                with Steve Engel.
% 2/25/99   dhb  Took out call to GetClut, no longer needed.
% 4/9/99    dhb  Modified to be cleaner, given my better understanding
%                of how the radius driver behaves.
% 5/8/99    dhb  Added 8-bit support.  Not tested for the measurement portion.
%                Indeed, the measurement portion has not been retested for any
%                mode after the change, although unless I made a typo it should
%                definitely work for 32-bit mode and probably for 8.
% 2/102     dhb  Change to use OpenWindow/SetClut.
% 4/17/02   dgp  Quit unless user has at least two screens.
% 4/18/02   dhb  Allow it to run with one screen by giving better prompts.
% 4/19/02   dgp  Cosmetic. Distinguish bits in DAC from pixelSize.
% 4/19/02   dgp  Speak when screen is too dark. Abort if two screens are needed.
% 4/24/02   awi  Exit on PC with message.
% 6/6/02    dgp  If necessary, change screen resolution.

if strcmp('PCWIN',computer)
    error('Win: TenBitClutTest not yet supported.');
end

% Open a window
whichScreen = max(Screen('Screens'));

% Set pixelSize to 8 or 32.  For CLUT animation, 32 requires
% just a setgamma call, without calling setclut.  For bitmap
% movies, you may want 8 bits, to reduce the amount of data that
% must be written.
pixelSize = 32;
oldRes=Screen(whichScreen,'Resolution');
res=oldRes;
res.pixelSize=pixelSize;
res=NearestResolution(whichScreen,res);
if res.mode~=oldRes.mode
	fprintf('Changing screen resolution to get %d-bit pixels.\n',pixelSize);
	SetResolution(whichScreen,res);
end

% Flags.  Don't set these to 1 unless you really know what you're doing.
CHECK_TABLES = 1;
CHECK_SQUARE = 0;
MEASURE_SQUARE = 0;

% Set up 8 and 10 bit cluts
offClut = zeros(256,3);
grayClut = (0:255)'*ones(1,3);
grayGamma = 4*grayClut;
lowGamma = (0:255)'*ones(1,3);
midGamma = lowGamma+128*3;
highGamma = lowGamma+(256*3);
grayGamma = 4*grayClut;
rgGamma = 4*[grayClut(:,1) grayClut(256:-1:1,1) zeros(size(grayClut(:,1)))];

% Open window and blank.  In 32-bit pixel mode
% the driver sets the gamma without waiting for SetClut.
[windowPtr,screenRect] = OpenWindow(whichScreen,0,[],pixelSize); 
stripeWidth = floor(screenRect(RectRight)/256);
for i=0:255
	theRect = [screenRect(RectLeft)+i*stripeWidth screenRect(rectTop) ...
						 screenRect(RectLeft)+(i+1)*stripeWidth screenRect(rectBottom)];
	Screen(windowPtr,'FillRect',i,theRect);
end
Screen(windowPtr,'SetClut',offClut);

% Adjust cluts for hardware
grayGamma = Adjust10BitClut(windowPtr,grayGamma);
lowGamma = Adjust10BitClut(windowPtr,lowGamma);
midGamma = Adjust10BitClut(windowPtr,midGamma);
highGamma = Adjust10BitClut(windowPtr,highGamma);
rgGamma = Adjust10BitClut(windowPtr,rgGamma);

SetClut(windowPtr,grayGamma);
Screen(windowPtr,'TextSize',24);
Ask(windowPtr,'Full gray ramp. Click to continue.                ');

% Check that setting gamma tables does good things.
% Note that it is not necessary to call 'SetClut' for
% the gamma table to take effect if pixelSize is 16 or 32.
if CHECK_TABLES

	% Pop them in	

	SetClut(windowPtr,lowGamma);
	Speak('Please click to continue.'); % Everything's black, so do it aurally.
	Ask(windowPtr,'lowGamma, dark ramp. Click to continue.                ');
	
	SetClut(windowPtr,midGamma);
	Ask(windowPtr,'midGamma, midrange ramp. Click to continue.                ');
	
	SetClut(windowPtr,highGamma);
	Ask(windowPtr,'highGamma, high range ramp. Click to continue.                ');
	
	SetClut(windowPtr,rgGamma);
	Ask(windowPtr,'rgGamma, red/green ramp. Click to continue.                ');

	SetClut(windowPtr,grayGamma);
	Ask(windowPtr,'grayGamma, full gray ramp. Click to continue.                ');
end
	
% Write a uniform field and a square one step away.
% This is an attempt to visually determine whether 
% the low bits are actually doing something.
if CHECK_SQUARE
	if whichScreen==0
		SetClut(windowPtr,grayGamma);
		CloseWindow(windowPtr); 
		error('Sorry, the CHECK_SQUARE option requires two screens.');
	end
	waitFrames = 9;
	nCycles = 100;
	bg = 0;
	rbase = 0;
	gbase = 510;
	bbase = 0;
	step = 100;
	Screen(windowPtr,'FillRect',0);
	Screen(windowPtr,'FillRect',1,CenterRect([0 0 200 200],screenRect));
	grayGamma(1,:) = Adjust10BitClut(windowPtr,[bg bg bg]);
	if MEASURE_SQUARE
		spectra = zeros(81,3,nCycles);
		CMCheckInit;
		grayGamma(2,:) = Adjust10BitClut(windowPtr,[1023 1023 1023]);
		SetClut(windowPtr,grayGamma);
		fprintf('Aim radiometer. Click when ready.\n');
	else
		grayGamma(2,:) = Adjust10BitClut(windowPtr,[rbase gbase bbase]);
		SetClut(windowPtr,grayGamma);
		fprintf('Ready to flicker. Click mouse.\n');
	end
	GetClicks;

	for i = 1:nCycles
		grayGamma(2,:) = Adjust10BitClut(windowPtr,[rbase gbase-step bbase]);
		SetClut(windowPtr,grayGamma);
		Screen(windowPtr,'WaitBlanking',waitFrames);
		if MEASURE_SQUARE
			fprintf('Measurements %g\n',i);
			fprintf('\tMeasuring %g less %g\n',gbase,step);
			spectra(:,1,i) = MeasSpd;
		end

		grayGamma(2,:) = Adjust10BitClut(windowPtr,[rbase gbase bbase]);
		SetClut(windowPtr,grayGamma);
		Screen(windowPtr,'WaitBlanking',waitFrames);
		if MEASURE_SQUARE
			fprintf('\tMeasuring %g\n',gbase);
			spectra(:,2,i) = MeasSpd;
		end

		grayGamma(2,:) = Adjust10BitClut(windowPtr,[rbase gbase+step bbase+step]);
		SetClut(windowPtr,grayGamma);
		Screen(windowPtr,'WaitBlanking',waitFrames);
		if MEASURE_SQUARE
			fprintf('\tMeasuring %g plus %g\n',gbase,step);
			spectra(:,3,i) = MeasSpd;
		end

		grayGamma(2,:) = Adjust10BitClut(windowPtr,[rbase gbase bbase]);
		SetClut(windowPtr,grayGamma);
		Screen(windowPtr,'WaitBlanking',waitFrames);
		if (KbCheck)
			break
		end
	end
	if CharAvail
		GetChar;
	end
	
	% Process spectra.  Do a t test on values near max to show that
	% a small step makes a measurable difference to light level.
	if MEASURE_SQUARE
		wls = SToWls([380 5 81]);
		meanSpectra = mean(spectra,3);
		useIndex = find(wls >= 500 & wls <= 560);
		% [nil,index] = max(spectra(:,2));
		% useIndex = [index(1)-3 index(1)-2 index(1)-1 index(1) index(1)+1 index(1)+2 index(1)+3];
		sumSpectra = sum(spectra(useIndex,:,:),1);
		diffs1 = squeeze(sumSpectra(:,2,:)-sumSpectra(:,1,:));
		diffs2 = squeeze(sumSpectra(:,3,:)-sumSpectra(:,2,:));
		[h1,sig1] = ttest(diffs1,0,0.01,0);
		[h2,sig2] = ttest(diffs2,0,0.01,0);
		fprintf('Z %g - %g, mean diff = %g, pSame = %g\n',gbase,step,mean(diffs1),sig1);
		fprintf('Z %g + %g, mean diff = %g, pSame = %g\n',gbase,step,mean(diffs2),sig2);
		
		% Plot spectra
		figure(1); clf;
		plot(SToWls([380 5 81]),meanSpectra(:,1),'r');
		hold on
		plot(SToWls([380 5 81]),meanSpectra(:,2),'g');
		plot(SToWls([380 5 81]),meanSpectra(:,3),'b');
		drawnow;
	end
end

% Close up the screen and exit.
SetClut(windowPtr,grayGamma);
CloseWindow(windowPtr);
if res.mode~=oldRes.mode
	fprintf('Restoring original screen resolution.\n');
	SetResolution(whichScreen,oldRes);
end


