Beispiel #1
0
PsychError GESTALTGestalt(void) 
{
	char					*selectorCString;
	OSType					selectorConstant;
	CFStringRef				selectorCFString;
	OSErr					callError;
	long					responseLong, i;
	PsychNativeBooleanType	*responseArray;
	psych_bool					returnResponse;

    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(1));
	
    PsychAllocInCharArg(1, kPsychArgRequired, &selectorCString);
	if( strlen(selectorCString) != 4)
		PsychErrorExitMsg(PsychError_user, "The selector code must be a four-character string");
	selectorCFString=CFStringCreateWithCString (NULL, selectorCString, kCFStringEncodingUTF8);
	selectorConstant= UTGetOSTypeFromString(selectorCFString); 
	callError= Gestalt(selectorConstant, &responseLong);
	CFRelease(selectorCFString);
	if(callError)
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)callError);
	else{
		returnResponse=PsychAllocOutBooleanMatArg(1, kPsychArgOptional, 1, 32, 1, &responseArray);
		if(returnResponse){
			for(i=0;i<32;i++){
				if(1<<i & responseLong) 
					responseArray[31-i]=TRUE;
				else
					responseArray[31-i]=FALSE;
			}
		}
	}
    return(PsychError_none);	
}
PsychError COCOAEVENTBRIDGEPathToBundle(void) 
{

	Boolean						isNewArgThereFlag;
	int							newNameLength;
	char						*tempBundleFilePathNameStr, *localBundleFilePathNameStr;
	

	//all subfunctions should have these two lines.  
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    //check to see if the user supplied superfluous arguments
    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(1));
	
	//first copy out the old path 
	GetPathToBundleString(&localBundleFilePathNameStr);
	PsychCopyOutCharArg(1, kPsychArgOptional, localBundleFilePathNameStr);
	
	//read in and retain the new name.  It arrives in a temporary variable
	isNewArgThereFlag=PsychAllocInCharArg(1, kPsychArgOptional, &tempBundleFilePathNameStr);
	if(isNewArgThereFlag){
		newNameLength=strlen(tempBundleFilePathNameStr);
		if(bundleFilePathNameStr != NULL)
			free((void*)bundleFilePathNameStr);
		bundleFilePathNameStr=(char*)malloc(sizeof(char) * (newNameLength + 1));
		strncpy(bundleFilePathNameStr, tempBundleFilePathNameStr, newNameLength + 1);
	}
		
    return(PsychError_none);	
}
Beispiel #3
0
// Open a serial port on a serial port device:
PsychError IOPORTConfigureSerialPort(void)
{
 	static char useString[] = "IOPort('ConfigureSerialPort', handle, configString);";
	static char synopsisString[] = 
		"(Re-)Configure a serial port device, specified by 'handle'.\n"
		"The string 'configString' is a string with pairs of paramName=paramValue "
		"tokens, separated by a delimiter, e.g., a space. It allows to specify specific "
		"values 'paramValue' to specific serial port parameters 'paramName'. Not all "
		"parameters are supported by all operating systems, and all settings have reasonable "
		"defaults. Settings unknown to a specific operating system are ignored.\n\n"
		"See the help of 'OpenSerialPort' for possible settings.";
		
	static char seeAlsoString[] = "'OpenSerialPort'";
	char* configString = NULL;
	PsychSerialDeviceRecord* device = NULL;
	int handle;
	
	// Setup online help: 
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none); };
	
	PsychErrorExit(PsychCapNumInputArgs(2));     // The maximum number of inputs
	PsychErrorExit(PsychRequireNumInputArgs(2)); // The required number of inputs	
	PsychErrorExit(PsychCapNumOutputArgs(0));	 // The maximum number of outputs

	// Get required portSpec:
	PsychCopyInIntegerArg(1, kPsychArgRequired, &handle);
	
	// Get the configString:
	PsychAllocInCharArg(2, kPsychArgRequired, &configString);
	
	// Return return value of configuration call:
	return(PsychIOOSConfigureSerialPort(PsychGetPortIORecord(handle)->device, configString));
}
/*  This function is called by the special subfunction 'DescribeModuleFunctionsHelper'.
 *  It returns the full table of registered subfunction names as an array.
 *  Useful for automatic documentation generators...
 *
 */
PsychError PsychDescribeModuleFunctions(void)
{
	static char useString[] = "subfunctionNames = Modulename('DescribeModuleFunctionsHelper' [, mode] [, subfunctionName]);";
	static char synopsisString[] = "Return a cell array of strings naming all subfunctions supported by this module if "
								   "the optional 'subfunctionName' argument is omitted. If 'subfunctionName' is a "
								   "string with a valid subfunction name for the module, and 'mode' is 1, return a 3 element cell "
								   "array of strings which describe the detailed syntax, help and see also strings "
								   "for that function - the text you'd get for Modulename('subfunctionName?'); ";
	static char seeAlsoString[] = "";

	char*						subfname;
    int							i;
    PsychGenericScriptType		*cellVector;
	PsychFunctionPtr			fcn;
	
    //all subfunctions should have these two lines.  
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    // Check for valid number of arguments
    PsychErrorExit(PsychCapNumInputArgs(2));   	
    PsychErrorExit(PsychCapNumOutputArgs(1)); 
    
	PsychCopyInIntegerArg(1, FALSE, &i);
	
	subfname = NULL;
	PsychAllocInCharArg(2, FALSE, &subfname);
	
	if (subfname) {
		// Find named subfunction in functin table:
		fcn = PsychGetProjectFunction(subfname);
		if (fcn) {
			// This will trigger the subfunction 'fcn' to execute its PsychGiveHelp() method, then
			// return. PsychGiveHelp() will return the help text to Runtime as cell array of strings,
			// instead of printing to runtimes console:
			PsychSetGiveHelp();
			PsychOneShotReturnHelp();
			(*fcn)();
			PsychClearGiveHelp();
		}
	}
	else {
		// Generate a cell array to return
		PsychAllocOutCellVector(1, FALSE, numFunctionsREGISTER,  &cellVector);
		for(i=0; i < numFunctionsREGISTER; i++) PsychSetCellVectorStringElement(i, functionTableREGISTER[i].name, cellVector);
	}
	        
    return(PsychError_none);
}
PsychError SCREENTextFont(void) 
{

    boolean			doSetByName, doSetByNumber, foundFont;
    PsychWindowRecordType	*windowRecord;
    PsychFontStructType		*fontRecord;
    int				oldTextFontNumber, inputTextFontNumber;
    char			*oldTextFontName, *inputTextFontName;
    
    //all subfunctions should have these two lines.  
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    //check for valid number of arguments
    PsychErrorExit(PsychRequireNumInputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(2));   	
    PsychErrorExit(PsychCapNumOutputArgs(2)); 
    
    //Get the window record
    PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
    
    //Save the old text size value and return it.
    oldTextFontNumber=windowRecord->textAttributes.textFontNumber;
    PsychCopyOutDoubleArg(2, FALSE, (double)oldTextFontNumber);
    oldTextFontName=windowRecord->textAttributes.textFontName;
    PsychCopyOutCharArg(1, FALSE, oldTextFontName); 
    
	
    //Fetch and set the new font if specified by name or number
    PsychCheckInputArgType(2, kPsychArgOptional, PsychArgType_double | PsychArgType_char);  //if the argument is there check that it is the right type.
    doSetByNumber= PsychCopyInIntegerArg(2, kPsychArgAnything, &inputTextFontNumber);
    doSetByName= PsychAllocInCharArg(2, kPsychArgAnything, &inputTextFontName);
    foundFont=0;
    if(doSetByNumber)
        foundFont=PsychGetFontRecordFromFontNumber(inputTextFontNumber, &fontRecord);
    if(doSetByName)
        foundFont=PsychGetFontRecordFromFontFamilyNameAndFontStyle(inputTextFontName, windowRecord->textAttributes.textStyle, &fontRecord);
    if(foundFont){
        strncpy(windowRecord->textAttributes.textFontName, fontRecord->fontFMFamilyName, 255);
        windowRecord->textAttributes.textFontNumber= fontRecord->fontNumber;
    }
    
    return(PsychError_none);

}
PsychError SCREENSetVideoCaptureParameter(void) 
{
    int capturehandle = -1;
    double value = DBL_MAX;
    double oldvalue;
    char* pname = NULL;

    // All sub functions should have these two lines
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none);};

    PsychErrorExit(PsychCapNumInputArgs(3));            // Max. 3 input args.
    PsychErrorExit(PsychRequireNumInputArgs(2));        // Min. 2 input args required.
    PsychErrorExit(PsychCapNumOutputArgs(1));           // One output arg.
    
    // Get the device handle:
    PsychCopyInIntegerArg(1, TRUE, &capturehandle);
    if (capturehandle==-1) {
        PsychErrorExitMsg(PsychError_user, "SetVideoCaptureParameter called without valid handle to a capture object.");
    }
    
    // Copy in parameter name string:
    PsychAllocInCharArg(2, TRUE, &pname);
    if (pname == NULL) {
        PsychErrorExitMsg(PsychError_user, "SetVideoCaptureParameter called without a parameter name string.");
    }

    // Copy in (optional) value for parameter:
    PsychCopyInDoubleArg(3, FALSE, &value);

    // Try to set parameter:
    oldvalue = PsychVideoCaptureSetParameter(capturehandle, pname, value);

    // Return old value of capture parameter:
    if (strstr(pname, "Get")==NULL) {
      PsychCopyOutDoubleArg(1, FALSE, oldvalue);
    }

    // Ready!    
    return(PsychError_none);
}
PsychError SCREENTextMode(void) 
{

    PsychTextDrawingModeType		newCopyMode;
    Str255							oldCopyModeName; 
    char							*newCopyModeName;
    psych_bool							doSetMode;
    PsychWindowRecordType			*windowRecord;
    psych_bool							nameError;                           
    
    //all subfunctions should have these two lines.  
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    //check for valid number of arguments
    PsychErrorExit(PsychRequireNumInputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(2));   	
    PsychErrorExit(PsychCapNumOutputArgs(1)); 
    
    //Get the window record
    PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
    
    //Get the old copy mode & its name
    PsychGetTextDrawingModeNameFromTextDrawingModeConstant(oldCopyModeName, 255, windowRecord->textAttributes.textMode);
    PsychCopyOutCharArg(1, FALSE, oldCopyModeName);
    
    //Get the copy new mode string 
    doSetMode= PsychAllocInCharArg(2, FALSE, &newCopyModeName);
    if(doSetMode){
        nameError=PsychGetTextDrawingModeConstantFromTextDrawingModeName(&newCopyMode, newCopyModeName);
        if(nameError)
            PsychErrorExitMsg(PsychError_user, "Invalid text copy mode.  See Screen('TextModes') for a list of allowable modes");
		windowRecord->textAttributes.needsRebuild|=(windowRecord->textAttributes.textMode != newCopyMode) ? TRUE : FALSE;
        windowRecord->textAttributes.textMode=newCopyMode;	
    }
	
    return(PsychError_none);
}
Beispiel #8
0
// Open a serial port on a serial port device:
PsychError IOPORTOpenSerialPort(void)
{
 	static char useString[] = "[handle, errmsg] = IOPort('OpenSerialPort', port [, configString]);";
	static char synopsisString[] = 
		"Open a serial port device, return a 'handle' to it.\n"
		"If a port can't be opened, the function will abort with error, unless the "
		"level of verbosity is set to zero, in which case the function will silently "
		"fail, but return an invalid (negative) handle to signal the failure to the "
		"calling script. The optional return argument 'errmsg' contains a text string "
		"which is either empty on success, or contains a descriptive error message. \n"
		"'port' is usually a name string that defines the serial port device "
		"to open. On MS-Windows this could be, e.g., 'COM1' or 'COM2' etc. On "
		"Apple OS/X, it is the path to a BSD device file, e.g., '/dev/cu.usbserial-FT3Z95V5' "
		"for a serial-over-USB device with unique id FT3Z95V5. On GNU/Linux it could be "
		"'/dev/ttyS0' for the first real serial port, or '/dev/ttyUSB0' for the first "
		"serial-over-USB device.\n\n"
		"The optional string 'configString' is a string with pairs of paramName=paramValue "
		"tokens, separated by a delimiter, e.g., a space. It allows to specify specific "
		"values 'paramValue' to specific serial port parameters 'paramName'. Not all "
		"parameters are supported by all operating systems, and all settings have reasonable "
		"defaults. Settings unknown to a specific operating system are ignored.\n"
		"The following is a list of (possibly) supported parameters with their defaults:\n\n"
		"BaudRate=9600 -- The baud transmission rate of the connection. Standard baud rates include "
		"110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200, 128000 and "
		"256000 bits per second. Not all values may be supported by all operating systems and drivers.\n\n"
		"Parity=None   -- Type of parity checking: None, Even, Odd.\n\n"
		"DataBits=8    -- Number of data bits per packet: 5,6,7 or 8, on Windows also 16.\n\n"
		"StopBits=1    -- Number of stop bits per packet: 1 or 2.\n\n"
		"FlowControl=None  -- Type of flow control: None, Hardware (RTS/CTS lines), Software (XON/XOFF characters).\n\n"
		"Terminator=os default  -- Type of terminator, given as ASCII character value, e.g., 13 for char(13) aka CR. Currently unused\n\n"
		"DTR=os default	-- Setting for 'Data Terminal Ready' pin: 0 or 1.\n\n"
		"RTS=os default	-- Setting for 'Request To Send' pin: 0 or 1.\n\n"
		"BreakBehaviour=Ignore -- Behaviour if a 'Break Condition' is detected on the line: Ignore, Flush, Zero. On Windows, this setting is ignored.\n\n"
		"OutputBufferSize=4096 -- Size of output buffer in bytes.\n\n"
		"InputBufferSize=4096 -- Size of input buffer in bytes. You can't read more than that amount per read command.\n\n"
		"HardwareBufferSizes=input,output -- Set size of the hardware driver internal input and output buffers in bytes. "
		"E.g., HardwareBufferSizes=32768,8192 would set the input buffer to 32768 bytes and the output buffer to 8192 bytes. "
		"This function is currently only supported on Windows, ignored on other systems. It is only a polite hint to the driver, "
		"the serial port driver is free to ignore the request and choose any buffer sizes or buffering strategy it finds appropriate. "
		"By default, this parameter is not set by IOPort and the hardware driver uses some built-in reasonable setting.\n\n"
		"The following timeout values are inter-byte timeouts. You specify how much time reception or "
		"transmission of a single byte is allowed to take. Timeout occurs if more than that time elapses "
		"between send/reception of two consecutive bytes or if the total amount of time exceeds the "
		"number of bytes, times the interbyte timeout value. A value of zero means not to use any timeout, "
		"in which case a blocking read or write may take forever. If a timeout occurs, the read or write "
		"operation will be aborted. \n"
		"Granularity of timeout settings is 100 msecs on OS/X and Linux, 1 msec on Windows, all values "
		"are rounded to the closest value matching that granularity. The minimal timeout is 100 msecs "
		"on OS/X and Linux, about 6 msecs on Windows.\n\n"
		"SendTimeout=1.0 -- Interbyte send timeout in seconds. Only used on Windows.\n\n"
		"ReceiveTimeout=1.0 -- Interbyte receive timeout in seconds.\n\n"
		"ReceiveLatency=0.000001 -- Latency in seconds for processing of new input bytes. Only used on OS/X.\n\n"
		"PollLatency=0.0005 (0.005 on Windows) -- Latency between polls in seconds for polling in some 'Read' operations.\n\n"
		"ProcessingMode=Raw -- Mode of input/output processing: Raw or Cooked. On Windows, only Raw (binary) mode is supported.\n\n"
		"StartBackgroundRead=readGranularity -- Enable asynchronous background read operations on the port. This is only supported "
		"on Linux and OS/X for now. A parallel background thread is started which tries to fetch 'readGranularity' bytes of data, "
		"polling the port every 'PollLatency' seconds for at least 'readGranularity' bytes of data. 'InputBufferSize' must be an "
		"integral multiple of 'readGranularity' for this to work. Later IOPort('Read') commands will pull collected data from "
		"the InputBuffer in quanta of at most 'readGranularity' bytes per invocation. This function is useful for background "
		"data collection from devices that stream some data at a constant rate. You set up background read, let the parallel "
		"thread do all data collection in the background and collect the data at the end of a session with a sequence of "
		"IOPort('Read') calls. This way, data collection doesn't clutter your main experiment script.\n\n"
		"StopBackgroundRead -- Stop running background read operation, discard all pending data.\n\n";

	static char seeAlsoString[] = "'CloseAll'";	 
  	
	#if PSYCH_SYSTEM == PSYCH_WINDOWS
	// Difference to Unices: PollLatency defaults to 5 msecs instead of 0.5 msecs due to shoddy windows scheduler:
	static char defaultConfig[] = "BaudRate=9600 Parity=None DataBits=8 StopBits=1 FlowControl=None PollLatency=0.005 ReceiveLatency=0.000001 SendTimeout=1.0 ReceiveTimeout=1.0 ProcessingMode=Raw BreakBehaviour=Ignore OutputBufferSize=4096 InputBufferSize=4096"; 
	#else
	static char defaultConfig[] = "BaudRate=9600 Parity=None DataBits=8 StopBits=1 FlowControl=None PollLatency=0.0005 ReceiveLatency=0.000001 SendTimeout=1.0 ReceiveTimeout=1.0 ProcessingMode=Raw BreakBehaviour=Ignore OutputBufferSize=4096 InputBufferSize=4096"; 
	#endif
	
	char		finalConfig[2000];
	char		errmsg[1024];
	char*		portSpec = NULL;
	char*		configString = NULL;
	PsychSerialDeviceRecord* device = NULL;
	int			handle;
	
	// Setup online help: 
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none); };
	
	PsychErrorExit(PsychCapNumInputArgs(2));     // The maximum number of inputs
	PsychErrorExit(PsychRequireNumInputArgs(1)); // The required number of inputs	
	PsychErrorExit(PsychCapNumOutputArgs(2));	 // The maximum number of outputs

	// Get required portSpec:
	PsychAllocInCharArg(1, kPsychArgRequired, &portSpec);
	
	// Get the optional configString:
	if (!PsychAllocInCharArg(2, kPsychArgOptional, &configString)) {
		// No config string specified: Assign default string:
		sprintf(finalConfig, "%s", defaultConfig);
	}
	else {
		// Config string provided: Prepend it to default string. That way, all settings
		// spec'd by usercode will override the defaultConfig, but non-specified settings
		// will be provided by defaultConfig:
		sprintf(finalConfig, "%s %s", configString, defaultConfig);		
	}
	
	// Search for a free slot:
	if (portRecordCount >= PSYCH_MAX_IOPORTS) PsychErrorExitMsg(PsychError_user, "Maximum number of open Input/Output ports exceeded.");
	
	// Iterate until end or free slot:
	for (handle=0; (handle < PSYCH_MAX_IOPORTS) && (portRecordBank[handle].portType); handle++);
	if (portRecordBank[handle].portType) PsychErrorExitMsg(PsychError_user, "Maximum number of open Input/Output ports exceeded.");
	// handle is index into our port record...

	// Call OS specific open routine for serial port:
	device = PsychIOOSOpenSerialPort(portSpec, finalConfig, errmsg);

	// Copy out optional errmsg string:
	PsychCopyOutCharArg(2, kPsychArgOptional, errmsg);
	
	if (device == NULL) {
		// Special case: Could not open port, but verbosity level is zero, no conventional
		// error return possible as this would clutter the console with output. Simply cancel
		// open op and return a negative handle to signal failure to user code:
		PsychCopyOutDoubleArg(1, kPsychArgRequired, -1);
		return(PsychError_none);
	}
	
	// If we reach this point, then device is the pointer to the class specific device struct and the
	// open operation was successfull. Build port struct:
	portRecordBank[handle].portType = kPsychIOPortSerial;
	portRecordBank[handle].device = (void*) device;
	portRecordCount++;
	
	// Return handle to new serial port object:
	PsychCopyOutDoubleArg(1, kPsychArgRequired, (double) handle);
	
    return(PsychError_none);
}
PsychError SCREENGetImage(void) 
{
	PsychRectType   windowRect,sampleRect;
	int 			nrchannels, ix, iy, sampleRectWidth, sampleRectHeight, invertedY, redReturnIndex, greenReturnIndex, blueReturnIndex, alphaReturnIndex, planeSize;
	int				viewid;
	ubyte 			*returnArrayBase, *redPlane, *greenPlane, *bluePlane, *alphaPlane;
	float 			*dredPlane, *dgreenPlane, *dbluePlane, *dalphaPlane;
	double 			*returnArrayBaseDouble;
	PsychWindowRecordType	*windowRecord;
	GLboolean		isDoubleBuffer, isStereo;
	char*           buffername = NULL;
	boolean			floatprecision = FALSE;
	GLenum			whichBuffer = 0; 
	
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//cap the numbers of inputs and outputs
	PsychErrorExit(PsychCapNumInputArgs(5));   //The maximum number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(1));  //The maximum number of outputs
	
	// Get windowRecord for this window:
	PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
	
	// Set window as drawingtarget: Even important if this binding is changed later on!
	// We need to make sure all needed transitions are done - esp. in non-imaging mode,
	// so backbuffer is in a useable state:
	PsychSetDrawingTarget(windowRecord);
	
	// Disable shaders:
	PsychSetShader(windowRecord, 0);

	// Soft-Reset drawingtarget. This is important to make sure no FBO's are bound,
	// otherwise the following glGets for GL_DOUBLEBUFFER and GL_STEREO will retrieve
	// wrong results, leading to totally wrong read buffer assignments down the road!!
	PsychSetDrawingTarget(0x1);

	glGetBooleanv(GL_DOUBLEBUFFER, &isDoubleBuffer);
	glGetBooleanv(GL_STEREO, &isStereo);
	
	// Retrieve optional read rectangle:
	PsychGetRectFromWindowRecord(windowRect, windowRecord);
	if(!PsychCopyInRectArg(2, FALSE, sampleRect)) memcpy(sampleRect, windowRect, sizeof(PsychRectType));
	if (IsPsychRectEmpty(sampleRect)) return(PsychError_none);
	
	// Assign read buffer:
	if(PsychIsOnscreenWindow(windowRecord)) {
		// Onscreen window: We read from the front- or front-left buffer by default.
		// This works on single-buffered and double buffered contexts in a consistent fashion:
		
		// Copy in optional override buffer name:
		PsychAllocInCharArg(3, FALSE, &buffername);
		
		// Override buffer name provided?
		if (buffername) {
			// Which one is it?
			
			// "frontBuffer" is always a valid choice:
			if (PsychMatch(buffername, "frontBuffer")) whichBuffer = GL_FRONT;
			// Allow selection of left- or right front stereo buffer in stereo mode:
			if (PsychMatch(buffername, "frontLeftBuffer") && isStereo) whichBuffer = GL_FRONT_LEFT;
			if (PsychMatch(buffername, "frontRightBuffer") && isStereo) whichBuffer = GL_FRONT_RIGHT;
			// Allow selection of backbuffer in double-buffered mode:
			if (PsychMatch(buffername, "backBuffer") && isDoubleBuffer) whichBuffer = GL_BACK;
			// Allow selection of left- or right back stereo buffer in stereo mode:
			if (PsychMatch(buffername, "backLeftBuffer") && isStereo && isDoubleBuffer) whichBuffer = GL_BACK_LEFT;
			if (PsychMatch(buffername, "backRightBuffer") && isStereo && isDoubleBuffer) whichBuffer = GL_BACK_RIGHT;
			// Allow AUX buffer access for debug purposes:
			if (PsychMatch(buffername, "aux0Buffer")) whichBuffer = GL_AUX0;
			if (PsychMatch(buffername, "aux1Buffer")) whichBuffer = GL_AUX1;
			if (PsychMatch(buffername, "aux2Buffer")) whichBuffer = GL_AUX2;
			if (PsychMatch(buffername, "aux3Buffer")) whichBuffer = GL_AUX3;			
		}
		else {
			// Default is frontbuffer:
			whichBuffer=GL_FRONT;
		}
	}
	else {
		// Offscreen window or texture: They only have one buffer, which is the
		// backbuffer in double-buffered mode and the frontbuffer in single buffered mode:
		whichBuffer=(isDoubleBuffer) ? GL_BACK : GL_FRONT;
	}
	
	// Enable this windowRecords framebuffer as current drawingtarget. This should
	// also allow us to "GetImage" from Offscreen windows:
	if ((windowRecord->imagingMode & kPsychNeedFastBackingStore) || (windowRecord->imagingMode & kPsychNeedFastOffscreenWindows)) {
		// Special case: Imaging pipeline active - We need to activate system framebuffer
		// so we really read the content of the framebuffer and not of some FBO:
		if (PsychIsOnscreenWindow(windowRecord)) {
			// It's an onscreen window:
			if (buffername && (PsychMatch(buffername, "drawBuffer")) && (windowRecord->imagingMode & kPsychNeedFastBackingStore)) {
				// Activate drawBufferFBO:
				PsychSetDrawingTarget(windowRecord);
				whichBuffer = GL_COLOR_ATTACHMENT0_EXT;
				
				// Is the drawBufferFBO multisampled?
				viewid = (((windowRecord->stereomode > 0) && (windowRecord->stereodrawbuffer == 1)) ? 1 : 0);
				if (windowRecord->fboTable[windowRecord->drawBufferFBO[viewid]]->multisample > 0) {
					// It is! We can't read from a multisampled FBO. Need to perform a multisample resolve operation and read
					// from the resolved unisample buffer instead. This is only safe if the unisample buffer is either a dedicated
					// FBO, or - in case its the final system backbuffer etc. - if preflip operations haven't been performed yet.
					// If non dedicated buffer (aka finalizedFBO) and preflip ops have already happened, then the backbuffer contains
					// final content for an upcoming Screen('Flip') and we can't use (and therefore taint) that buffer.
					if ((windowRecord->inputBufferFBO[viewid] == windowRecord->finalizedFBO[viewid]) && (windowRecord->backBufferBackupDone)) {
						// Target for resolve is finalized FBO (probably system backbuffer) and preflip ops have run already. We
						// can't do the resolve op, as this would screw up the backbuffer with the final stimulus:
						printf("PTB-ERROR: Tried to 'GetImage' from a multisampled 'drawBuffer', but can't perform anti-aliasing pass due to\n");
						printf("PTB-ERROR: lack of a dedicated resolve buffer.\n");
						printf("PTB-ERROR: You can get what you wanted by either one of two options:\n");
						printf("PTB-ERROR: Either enable a processing stage in the imaging pipeline, even if you don't need it, e.g., by setting\n");
						printf("PTB-ERROR: the imagingmode argument in the 'OpenWindow' call to kPsychNeedImageProcessing, this will create a\n");
						printf("PTB-ERROR: suitable resolve buffer. Or place the 'GetImage' call before any Screen('DrawingFinished') call, then\n");
						printf("PTB-ERROR: i can (ab-)use the system backbuffer as a temporary resolve buffer.\n\n");
						PsychErrorExitMsg(PsychError_user, "Tried to 'GetImage' from a multi-sampled 'drawBuffer'. Unsupported operation under given conditions.");						
					}
					else {
						// Ok, the inputBufferFBO is a suitable temporary resolve buffer. Perform a multisample resolve blit to it:
						// A simple glBlitFramebufferEXT() call will do the copy & downsample operation:
						glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, windowRecord->fboTable[windowRecord->drawBufferFBO[viewid]]->fboid);
						glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, windowRecord->fboTable[windowRecord->inputBufferFBO[viewid]]->fboid);
						glBlitFramebufferEXT(0, 0, windowRecord->fboTable[windowRecord->inputBufferFBO[viewid]]->width, windowRecord->fboTable[windowRecord->inputBufferFBO[viewid]]->height,
											 0, 0, windowRecord->fboTable[windowRecord->inputBufferFBO[viewid]]->width, windowRecord->fboTable[windowRecord->inputBufferFBO[viewid]]->height,
											 GL_COLOR_BUFFER_BIT, GL_NEAREST);

						// Bind inputBuffer as framebuffer:
						glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, windowRecord->fboTable[windowRecord->inputBufferFBO[viewid]]->fboid);
						viewid = -1;
					}
				}
			}
			else {
				// Activate system framebuffer:
				PsychSetDrawingTarget(NULL);
			}
		}
		else {
			// Offscreen window or texture: Select drawing target as usual,
			// but set color attachment as read buffer:
			PsychSetDrawingTarget(windowRecord);
			whichBuffer = GL_COLOR_ATTACHMENT0_EXT;

			// We do not support multisampled readout:
			if (windowRecord->fboTable[windowRecord->drawBufferFBO[0]]->multisample > 0) {
				printf("PTB-ERROR: You tried to Screen('GetImage', ...); from an offscreen window or texture which has multisample anti-aliasing enabled.\n");
				printf("PTB-ERROR: This operation is not supported. You must first use Screen('CopyWindow') to create a non-multisampled copy of the\n");
				printf("PTB-ERROR: texture or offscreen window, then use 'GetImage' on that copy. The copy will be anti-aliased, so you'll get what you\n");
				printf("PTB-ERROR: wanted with a bit more effort. Sorry for the inconvenience, but this is mostly a hardware limitation.\n\n");
				
				PsychErrorExitMsg(PsychError_user, "Tried to 'GetImage' from a multi-sampled texture or offscreen window. Unsupported operation.");
			}
		}
	}
	else {
		// Normal case: No FBO based imaging - Select drawing target as usual:
		PsychSetDrawingTarget(windowRecord);
	}
	
	// Select requested read buffer, after some double-check:
	if (whichBuffer == 0) PsychErrorExitMsg(PsychError_user, "Invalid or unknown 'bufferName' argument provided.");
	glReadBuffer(whichBuffer);
	
	if (PsychPrefStateGet_Verbosity() > 5) printf("PTB-DEBUG: In Screen('GetImage'): GL-Readbuffer whichBuffer = %i\n", whichBuffer);

	// Get optional floatprecision flag: We return data with float-precision if
	// this flag is set. By default we return uint8 data:
	PsychCopyInFlagArg(4, FALSE, &floatprecision);
	
	// Get the optional number of channels flag: By default we return 3 channels,
	// the Red, Green, and blue color channel:
	nrchannels = 3;
	PsychCopyInIntegerArg(5, FALSE, &nrchannels);
	if (nrchannels < 1 || nrchannels > 4) PsychErrorExitMsg(PsychError_user, "Number of requested channels 'nrchannels' must be between 1 and 4!");
	
	sampleRectWidth=PsychGetWidthFromRect(sampleRect);
	sampleRectHeight=PsychGetHeightFromRect(sampleRect);
	
	if (!floatprecision) {
		// Readback of standard 8bpc uint8 pixels:  
		PsychAllocOutUnsignedByteMatArg(1, TRUE, sampleRectHeight, sampleRectWidth, nrchannels, &returnArrayBase);
		redPlane= PsychMallocTemp(nrchannels * sizeof(GL_UNSIGNED_BYTE) * sampleRectWidth * sampleRectHeight);
		planeSize=sampleRectWidth * sampleRectHeight;
		greenPlane= redPlane + planeSize;
		bluePlane= redPlane + 2 * planeSize;
		alphaPlane= redPlane + 3 * planeSize; 
		glPixelStorei(GL_PACK_ALIGNMENT,1);
		invertedY=windowRect[kPsychBottom]-sampleRect[kPsychBottom];
		glReadPixels(sampleRect[kPsychLeft],invertedY, 	sampleRectWidth, sampleRectHeight, GL_RED, GL_UNSIGNED_BYTE, redPlane); 
		if (nrchannels>1) glReadPixels(sampleRect[kPsychLeft],invertedY,	sampleRectWidth, sampleRectHeight, GL_GREEN, GL_UNSIGNED_BYTE, greenPlane);
		if (nrchannels>2) glReadPixels(sampleRect[kPsychLeft],invertedY,	sampleRectWidth, sampleRectHeight, GL_BLUE, GL_UNSIGNED_BYTE, bluePlane);
		if (nrchannels>3) glReadPixels(sampleRect[kPsychLeft],invertedY,	sampleRectWidth, sampleRectHeight, GL_ALPHA, GL_UNSIGNED_BYTE, alphaPlane);
		
		//in one pass transpose and flip what we read with glReadPixels before returning.  
		//-glReadPixels insists on filling up memory in sequence by reading the screen row-wise whearas Matlab reads up memory into columns.
		//-the Psychtoolbox screen as setup by gluOrtho puts 0,0 at the top left of the window but glReadPixels always believes that it's at the bottom left.     
		for(ix=0;ix<sampleRectWidth;ix++){
			for(iy=0;iy<sampleRectHeight;iy++){
				// Compute write-indices for returned data:
				redReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth, nrchannels, iy, ix, 0);
				greenReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth,  nrchannels, iy, ix, 1);
				blueReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth,  nrchannels, iy, ix, 2);
				alphaReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth,  nrchannels, iy, ix, 3);
				
				// Always return RED/LUMINANCE channel:
				returnArrayBase[redReturnIndex]=redPlane[ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth];  
				// Other channels on demand:
				if (nrchannels>1) returnArrayBase[greenReturnIndex]=greenPlane[ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth];
				if (nrchannels>2) returnArrayBase[blueReturnIndex]=bluePlane[ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth];
				if (nrchannels>3) returnArrayBase[alphaReturnIndex]=alphaPlane[ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth];
			}
		}		
	}
	else {
		// Readback of standard 32bpc float pixels into a double matrix:  
		PsychAllocOutDoubleMatArg(1, TRUE, sampleRectHeight, sampleRectWidth, nrchannels, &returnArrayBaseDouble);
		dredPlane= PsychMallocTemp(nrchannels * sizeof(GL_FLOAT) * sampleRectWidth * sampleRectHeight);
		planeSize=sampleRectWidth * sampleRectHeight * sizeof(GL_FLOAT);
		dgreenPlane= redPlane + planeSize;
		dbluePlane= redPlane + 2 * planeSize;
		dalphaPlane= redPlane + 3 * planeSize; 
		glPixelStorei(GL_PACK_ALIGNMENT, 1);
		invertedY=windowRect[kPsychBottom]-sampleRect[kPsychBottom];
		if (nrchannels==1) glReadPixels(sampleRect[kPsychLeft],invertedY, 	sampleRectWidth, sampleRectHeight, GL_RED, GL_FLOAT, dredPlane); 
		if (nrchannels==2) glReadPixels(sampleRect[kPsychLeft],invertedY,	sampleRectWidth, sampleRectHeight, GL_LUMINANCE_ALPHA, GL_FLOAT, dredPlane);
		if (nrchannels==3) glReadPixels(sampleRect[kPsychLeft],invertedY,	sampleRectWidth, sampleRectHeight, GL_RGB, GL_FLOAT, dredPlane);
		if (nrchannels==4) glReadPixels(sampleRect[kPsychLeft],invertedY,	sampleRectWidth, sampleRectHeight, GL_RGBA, GL_FLOAT, dredPlane);
		
		//in one pass transpose and flip what we read with glReadPixels before returning.  
		//-glReadPixels insists on filling up memory in sequence by reading the screen row-wise whearas Matlab reads up memory into columns.
		//-the Psychtoolbox screen as setup by gluOrtho puts 0,0 at the top left of the window but glReadPixels always believes that it's at the bottom left.     
		for(ix=0;ix<sampleRectWidth;ix++){
			for(iy=0;iy<sampleRectHeight;iy++){
				// Compute write-indices for returned data:
				redReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth, nrchannels, iy, ix, 0);
				greenReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth,  nrchannels, iy, ix, 1);
				blueReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth,  nrchannels, iy, ix, 2);
				alphaReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth,  nrchannels, iy, ix, 3);
				
				// Always return RED/LUMINANCE channel:
				returnArrayBaseDouble[redReturnIndex]=dredPlane[(ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth) * nrchannels + 0];  
				// Other channels on demand:
				if (nrchannels>1) returnArrayBaseDouble[greenReturnIndex]=dredPlane[(ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth) * nrchannels + 1];
				if (nrchannels>2) returnArrayBaseDouble[blueReturnIndex]=dredPlane[(ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth) * nrchannels + 2];
				if (nrchannels>3) returnArrayBaseDouble[alphaReturnIndex]=dredPlane[(ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth) * nrchannels + 3];
			}
		}		
	}
	
	if (viewid == -1) {
		// Need to reset framebuffer binding to get rid of the inputBufferFBO which is bound due to
		// multisample resolve ops --> Activate system framebuffer:
		PsychSetDrawingTarget(NULL);		
	}

	return(PsychError_none);
}
PsychError SCREENPreference(void)  
{

	PsychArgFormatType		arg1Type;
	char					*preferenceName, *newFontName;
	const char				*tableCreator, *oldDefaultFontName;
	psych_bool				preferenceNameArgumentValid, booleanInput, ignoreCase, tempFlag, textAlphaBlendingFlag, suppressAllWarningsFlag;
	int						numInputArgs, i, newFontStyleNumber, newFontSize, tempInt, tempInt2, tempInt3, tempInt4;
	double					returnDoubleValue, inputDoubleValue;
	double					maxStddev, maxDeviation, maxDuration;
	int						minSamples;
    double                  *dheads = NULL;

	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous or missing arguments
	PsychErrorExit(PsychCapNumInputArgs(5));			
	PsychErrorExit(PsychRequireNumInputArgs(1));		   
	PsychErrorExit(PsychCapNumOutputArgs(4));
	
	numInputArgs=PsychGetNumInputArgs();
	arg1Type=PsychGetArgType(1);
	preferenceNameArgumentValid=FALSE;
	
	//Cases which require both a window pointer or screen number and preference name.  Argument 1 is the wposn and argument 2 is the preference name.
	if( numInputArgs >= 2 && (PsychIsScreenNumberArg(1) || PsychIsScreenNumberArg(1)) && PsychGetArgType(2)==PsychArgType_char ){
		PsychAllocInCharArg(2, kPsychArgRequired, &preferenceName);
		//preferences which require window pointer or screen number argument which we DO NOT support  
		for(i=0;i<kPsychNumUnsupportedMacVideoPreferences;i++){
			if(PsychMatch(preferenceName, unsupportedMacVideoPreferenceNames[i]))
				PsychErrorExit(PsychError_unsupportedOS9Preference);
		}
		//insert here conditionals  to act on prefernces which accept a window pointer or screen number argument which we DO support.
		PsychErrorExit(PsychError_unrecognizedPreferenceName);
	}

	//Cases which do not require a wposn.  Argument 1 is the preference name.  if present Argument 2 is the new value
	if(arg1Type==PsychArgType_char){
		PsychAllocInCharArg(1, kPsychArgRequired, &preferenceName);
		//Preferernces which we do not support and which do not require a wposn
		for(i=0;i<kPsychNumUnsupportedMacNonVideoPreferences;i++){
			if(PsychMatch(preferenceName, unsupportedMacNonVideoPreferenceNames[i]))
				PsychErrorExit(PsychError_unsupportedOS9Preference);
		}
		//Preferences which we do support
		if(PsychMatch(preferenceName, "IgnoreCase")){
			ignoreCase=!PsychIsPsychMatchCaseSensitive();
			PsychCopyOutFlagArg(1, kPsychArgOptional, ignoreCase);
			if(numInputArgs==2){
				PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
				PsychSetPsychMatchCaseSenstive(!booleanInput);			
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "Tick0Secs")){
			if(PsychCopyInDoubleArg(2, kPsychArgOptional, &inputDoubleValue) && inputDoubleValue==PsychGetNanValue())
				PsychEstimateGetSecsValueAtTickCountZero();
			returnDoubleValue=PsychGetEstimatedSecsValueAtTickCountZero();
			PsychCopyOutDoubleArg(1, kPsychArgOptional, returnDoubleValue);
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "PsychTableVersion")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)PsychPrefStateGet_PsychTableVersion());
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "PsychTableCreator")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			tableCreator=PsychPrefStateGet_PsychTableCreator();
			PsychCopyOutCharArg(1, kPsychArgOptional, tableCreator);
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "Process")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) (psych_int64) getpid());
			preferenceNameArgumentValid=TRUE;


		}else 
		if(PsychMatch(preferenceName, "DefaultFontName")){
			PsychPrefStateGet_DefaultFontName(&oldDefaultFontName);
			PsychCopyOutCharArg(1, kPsychArgOptional, oldDefaultFontName);
			if(numInputArgs==2){
				PsychAllocInCharArg(2, kPsychArgRequired, &newFontName);
				PsychPrefStateSet_DefaultFontName(newFontName);
			}
			preferenceNameArgumentValid=TRUE;			
		}else 
		if(PsychMatch(preferenceName, "TextEncodingLocale")){
			PsychCopyOutCharArg(1, kPsychArgOptional, PsychGetUnicodeTextConversionLocale());
			if(numInputArgs==2){
				PsychAllocInCharArg(2, kPsychArgRequired, &newFontName);
				if (!PsychSetUnicodeTextConversionLocale(newFontName)) PsychErrorExitMsg(PsychError_user, "Setting the 'TextEncodingLocale' failed, most likely because you provided an invalid/unknown locale setting string.");
			}
			preferenceNameArgumentValid=TRUE;			
		}else 
		if(PsychMatch(preferenceName, "DefaultFontStyle")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DefaultTextStyle());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &newFontStyleNumber);
				PsychPrefStateSet_DefaultTextStyle(newFontStyleNumber);
			}
			preferenceNameArgumentValid=TRUE;
		}else
		if(PsychMatch(preferenceName, "OverrideMultimediaEngine")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_UseGStreamer());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_UseGStreamer(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else
		if(PsychMatch(preferenceName, "DefaultTextYPositionIsBaseline")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_TextYPositionIsBaseline());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_TextYPositionIsBaseline(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "TextAntiAliasing")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_TextAntiAliasing());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_TextAntiAliasing(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "TextRenderer")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_TextRenderer());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_TextRenderer(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "DefaultFontSize")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DefaultTextSize());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &newFontSize);
				PsychPrefStateSet_DefaultTextSize(newFontSize);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "DebugMakeTexture")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DebugMakeTexture());
			if(numInputArgs==2){
				PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
				PsychPrefStateSet_DebugMakeTexture(tempFlag);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SkipSyncTests")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_SkipSyncTests());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_SkipSyncTests(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VisualDebugLevel")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VisualDebugLevel());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_VisualDebugLevel(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VBLTimestampingMode")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VBLTimestampingMode());
			if(numInputArgs>=2){
                            PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
                            PsychPrefStateSet_VBLTimestampingMode(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SyncTestSettings")){
			PsychPrefStateGet_SynctestThresholds(&maxStddev, &minSamples, &maxDeviation, &maxDuration);
			PsychCopyOutDoubleArg(1, kPsychArgOptional, maxStddev);
			PsychCopyOutDoubleArg(2, kPsychArgOptional, minSamples);
			PsychCopyOutDoubleArg(3, kPsychArgOptional, maxDeviation);
			PsychCopyOutDoubleArg(4, kPsychArgOptional, maxDuration);
			if(numInputArgs>=2){
							PsychCopyInDoubleArg( 2, kPsychArgOptional, &maxStddev);
                            PsychCopyInIntegerArg(3, kPsychArgOptional, &minSamples);
							PsychCopyInDoubleArg( 4, kPsychArgOptional, &maxDeviation);
							PsychCopyInDoubleArg( 5, kPsychArgOptional, &maxDuration);
							PsychPrefStateSet_SynctestThresholds(maxStddev, minSamples, maxDeviation, maxDuration);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VBLEndlineOverride")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VBLEndlineOverride());
			if(numInputArgs>=2){
                            PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
                            PsychPrefStateSet_VBLEndlineOverride(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else
			if(PsychMatch(preferenceName, "DefaultVideocaptureEngine")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VideoCaptureEngine());
				if(numInputArgs==2){
					PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
					PsychPrefStateSet_VideoCaptureEngine(tempInt);
				}
			preferenceNameArgumentValid=TRUE;
		}else
			if(PsychMatch(preferenceName, "WindowShieldingLevel")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_WindowShieldingLevel());
				if(numInputArgs==2){
					PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
					PsychPrefStateSet_WindowShieldingLevel(tempInt);
				}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "ConserveVRAM") || PsychMatch(preferenceName, "Workarounds1")){
					PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_ConserveVRAM());
					if(numInputArgs==2){
						PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
						PsychPrefStateSet_ConserveVRAM(tempInt);
					}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "Verbosity")){
					PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_Verbosity());
					if(numInputArgs==2){
						PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
						PsychPrefStateSet_Verbosity(tempInt);
					}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "FrameRectCorrection")){
					PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_FrameRectCorrection());
					if(numInputArgs==2){
						PsychCopyInDoubleArg(2, kPsychArgRequired, &inputDoubleValue);
						PsychPrefStateSet_FrameRectCorrection(inputDoubleValue);
					}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "EmulateOldPTB")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_EmulateOldPTB());
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
					PsychPrefStateSet_EmulateOldPTB(tempFlag);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "Enable3DGraphics")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_3DGfx());
				if(numInputArgs==2){
					PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
					PsychPrefStateSet_3DGfx(tempInt);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "TextAlphaBlending")){
				textAlphaBlendingFlag=PsychPrefStateGet_TextAlphaBlending();
				PsychCopyOutFlagArg(1, kPsychArgOptional, textAlphaBlendingFlag);
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
					PsychPrefStateSet_TextAlphaBlending(booleanInput);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SuppressAllWarnings")){
				suppressAllWarningsFlag=PsychPrefStateGet_SuppressAllWarnings();
				PsychCopyOutFlagArg(1, kPsychArgOptional, suppressAllWarningsFlag);
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
					PsychPrefStateSet_SuppressAllWarnings(booleanInput);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SynchronizeDisplays")){
				if(numInputArgs >= 2) {
					// This is a special call: It currently doesn't set a preference setting,
					// but instead triggers an instantaneous synchronization of all available
					// display heads, if possible. We may have a more clever and "standard" interface
					// interface for this later on, but for first tests this will do.
					// Syncmethod is hard-coded to 0 -> Use whatever's available to sync.
					// timeout for retries is 5.0 seconds.
					// Acceptable residual offset is +/- 2 scanlines.
					// Returns the real residual offset after sync.
					PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
					if (!PsychCopyInIntegerArg(3, kPsychArgOptional, &tempInt3)) {
                        // No screenId specified: Resync default screen or whatever...
                        tempInt2 = 0;
                        if (PsychSynchronizeDisplayScreens(&tempInt2, NULL, &tempInt, tempInt, 5.0, 2)!=PsychError_none) PsychErrorExitMsg(PsychError_user, "Sync failed for reasons mentioned above.");
                    } else {
                        // Specific screenId provided: Resync crtc's associated with this screenId if possible:
                        tempInt2 = 1;
                        if (PsychSynchronizeDisplayScreens(&tempInt2, &tempInt3, &tempInt, tempInt, 5.0, 2)!=PsychError_none) PsychErrorExitMsg(PsychError_user, "Sync failed for reasons mentioned above.");
                    }
                    
					PsychCopyOutDoubleArg(1, kPsychArgOptional, tempInt);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "ScreenToHead")){
				// screenId is required:
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				if (tempInt < 0 || tempInt >= PsychGetNumDisplays() || tempInt >= kPsychMaxPossibleDisplays) PsychErrorExitMsg(PsychError_user, "Invalid screenId provided. Out of valid range!");

				// Return old mappings for this screenId:
                for (tempInt2 = 0; (tempInt2 < kPsychMaxPossibleCrtcs) && (PsychPrefStateGet_ScreenToHead(tempInt, tempInt2) >= 0); tempInt2++);
                PsychAllocOutDoubleMatArg(1, kPsychArgOptional, 2, tempInt2, 1, &dheads);
                
                tempInt4 = 0;
                for (tempInt3 = 0; tempInt3 < tempInt2; tempInt3++) {
                    dheads[tempInt4++] = (double) PsychPrefStateGet_ScreenToHead(tempInt, tempInt3);
                    dheads[tempInt4++] = (double) PsychPrefStateGet_ScreenToCrtcId(tempInt, tempInt3);
                }
                
                // Optionally retrieve and set new mappings for this screenId:
				if(numInputArgs>=3) {
					// Set new headId for screenId:
					PsychCopyInIntegerArg(3, kPsychArgRequired, &tempInt2);
					if (tempInt2 < 0) PsychErrorExitMsg(PsychError_user, "Invalid negative headId provided!");

					// Set new crtcId for screenId:
					PsychCopyInIntegerArg(4, kPsychArgRequired, &tempInt3);
					if (tempInt3 < 0) PsychErrorExitMsg(PsychError_user, "Invalid negative crtcId provided!");

                    // Assign primary head by default (index 0), but allow optionally others as well:
                    tempInt4 = 0;
					PsychCopyInIntegerArg(5, kPsychArgOptional, &tempInt4);
					if (tempInt4 < 0 || tempInt4 >= kPsychMaxPossibleCrtcs) PsychErrorExitMsg(PsychError_user, "Invalid rankId provided! Too many heads for one screen!");

					PsychPrefStateSet_ScreenToHead(tempInt, tempInt2, tempInt3, tempInt4);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			PsychErrorExit(PsychError_unrecognizedPreferenceName);
	}
	
	if(!preferenceNameArgumentValid)
		PsychErrorExitMsg(PsychError_user, "Invalid arguments to preferences command");
		
	return(PsychError_none);
}
PsychError SCREENOpenMovie(void) 
{
        PsychWindowRecordType					*windowRecord;
        char                                    *moviefile;
        int                                     moviehandle = -1;
        int                                     framecount;
        double                                  durationsecs;
        double                                  framerate;
        int                                     width;
        int                                     height;
        int                                     asyncFlag = 0;
        static psych_bool                       firstTime = TRUE;
		double									preloadSecs = 1;
        int										rc;

        if (firstTime) {
            // Setup asyncopeninfo on first invocation:
            firstTime = FALSE;
            asyncmovieinfo.asyncstate = 0; // State = No async open in progress.
        }
        
		// All sub functions should have these two lines
		PsychPushHelp(useString, synopsisString, seeAlsoString);
		if(PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none);};

        PsychErrorExit(PsychCapNumInputArgs(4));            // Max. 4 input args.
        PsychErrorExit(PsychRequireNumInputArgs(1));        // Min. 1 input args required.
        PsychErrorExit(PsychCapNumOutputArgs(6));           // Max. 6 output args.
        
        // Get the window record from the window record argument and get info from the window record
		windowRecord = NULL;
        PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, FALSE, &windowRecord);
        // Only onscreen windows allowed:
        if(windowRecord && !PsychIsOnscreenWindow(windowRecord)) {
            PsychErrorExitMsg(PsychError_user, "OpenMovie called on something else than an onscreen window.");
        }
        
        // Get the movie name string:
        moviefile = NULL;
        PsychAllocInCharArg(2, kPsychArgRequired, &moviefile);

        // Get the (optional) asyncFlag:
        PsychCopyInIntegerArg(3, FALSE, &asyncFlag);

		PsychCopyInDoubleArg(4, FALSE, &preloadSecs);
		if (preloadSecs < 0 && preloadSecs!= -1) PsychErrorExitMsg(PsychError_user, "OpenMovie called with invalid (negative, but not equal -1) 'preloadSecs' argument!");

        // Asynchronous Open operation in progress or requested?
        if ((asyncmovieinfo.asyncstate == 0) && (asyncFlag == 0)) {
            // No. We should just synchronously open the movie:

            // Try to open the named 'moviefile' and create & initialize a corresponding movie object.
            // A MATLAB handle to the movie object is returned upon successfull operation.
            PsychCreateMovie(windowRecord, moviefile, preloadSecs, &moviehandle);
        }
        else {
            // Asynchronous open operation requested or running:
            switch(asyncmovieinfo.asyncstate) {
                case 0: // No async open running, but async open requested
                    // Fill all information needed for opening the movie into the info struct:
                    asyncmovieinfo.asyncstate = 1; // Mark state as "Operation in progress"
                    asyncmovieinfo.moviename = strdup(moviefile);
					asyncmovieinfo.preloadSecs = preloadSecs;
                    if (windowRecord) {
						memcpy(&asyncmovieinfo.windowRecord, windowRecord, sizeof(PsychWindowRecordType));
					} else {
						memcpy(&asyncmovieinfo.windowRecord, 0, sizeof(PsychWindowRecordType));
					}

                    asyncmovieinfo.moviehandle = -1;

                    // Increase our scheduling priority to maximum FIFO priority: This way we should get
                    // more cpu time for our PTB main thread than the async. background prefetch-thread:
                    if ((rc=PsychSetThreadPriority(NULL, 1, 0))!=0) {
                        printf("PTB-WARNING: In OpenMovie(): Failed to raise priority of main thread [System error %i]. Expect movie timing problems.\n", rc);
                    }

                    // Start our own movie loader Posix-Thread:
                    PsychCreateThread(&asyncmovieinfo.pid, NULL, PsychAsyncCreateMovie, &asyncmovieinfo);
                    
                    // Async movie open initiated. We return control to host environment:
                    return(PsychError_none);
                break;
                    
                case 1: // Async open operation in progress, but not yet finished.
                    // Should we wait for completion or just return?
                    if (asyncFlag) {
                        // Async poll requested. We just return -1 to signal that open isn't finished yet:
                        PsychCopyOutDoubleArg(1, TRUE, -1);
                        return(PsychError_none);
                    }
                    // We fall through to case 2 - Wait for "Load operation successfully finished."
                
                case 2: // Async open operation successfully finished. Parse asyncinfo struct and return it to host environment:
                    // We need to join our terminated worker thread to release its ressources. If the worker-thread
                    // isn't done yet (fallthrough from case 1 for sync. wait), this join will block us until worker
                    // completes:
					PsychDeleteThread(&asyncmovieinfo.pid);
					
                    // Reset our priority to "normal" after async prefetch completion:
                    if ((rc=PsychSetThreadPriority(NULL, 0, 0))!=0) {
                        printf("PTB-WARNING: In OpenMovie(): Failed to lower priority of main thread [System error %i]. Expect movie timing problems.\n", rc);
                    }

                    asyncmovieinfo.asyncstate = 0; // Reset state to idle:
                    moviehandle = asyncmovieinfo.moviehandle;
                    
                    // Movie successfully opened?
                    if (moviehandle < 0) {
                        // Movie loading failed for some reason.
                        printf("PTB-ERROR: When trying to asynchronously load movie %s, the operation failed: ", asyncmovieinfo.moviename);
                        switch(moviehandle) {
                            case -2000:
                            case -50:
                            case -43:
                                printf("File not found.");
                                break;
                                
                            case -2048:
                                printf("This is not a file that Quicktime understands.");
                                break;
                                
                            case -2003:
                                printf("Can't find media handler (codec) for this movie.");
                                break;
                                
                            case -2:
                                printf("Maximum allowed number of simultaneously open movie files exceeded!");
                                break;
                                
                            case -1:
                                printf("Internal error: Failure in PTB's movie playback engine!");
                                break;
                                
                            default:
                                printf("Unknown error (Quicktime error %i): Check http://developer.apple.com/documentation/QuickTime/APIREF/ErrorCodes.htm#//apple_ref/doc/constant_group/Error_Codes", moviehandle);
                        }
                        printf("\n\n");
                        
                        PsychErrorExitMsg(PsychError_user, "Asynchronous loading of the Quicktime movie failed.");
                    }
                    
                    // We can fall out of the switch statement and continue with the standard synchronous load code as if
                    // the movie had been loaded synchronously.
                break;
                default:
                    PsychErrorExitMsg(PsychError_internal, "Unhandled async movie state condition encountered! BUG!!");
            }
        }

        // Upon sucessfull completion, we'll have a valid handle in 'moviehandle'.
        // Return it to Matlab-world:
        PsychCopyOutDoubleArg(1, TRUE, (double) moviehandle);

        // Retrieve infos about new movie:
        
        // Is the "count" output argument (total number of frames) requested by user?
        if (PsychGetNumOutputArgs() > 5) {
            // Yes. Query the framecount (expensive!) and return it:
            PsychGetMovieInfos(moviehandle, &width, &height, &framecount, &durationsecs, &framerate, NULL);
            PsychCopyOutDoubleArg(6, TRUE, (double) framecount);
        }
        else {
            // No. Don't compute and return it.
            PsychGetMovieInfos(moviehandle, &width, &height, NULL, &durationsecs, &framerate, NULL);
        }

        PsychCopyOutDoubleArg(2, FALSE, (double) durationsecs);
        PsychCopyOutDoubleArg(3, FALSE, (double) framerate);
        PsychCopyOutDoubleArg(4, FALSE, (double) width);
        PsychCopyOutDoubleArg(5, FALSE, (double) height);

		// Ready!
		return(PsychError_none);
}
PsychError SCREENTextBounds(void) 
{
	//for debugging
	TextEncodingBase		textEncodingBase;
	TextEncodingVariant		textEncodingVariant;
	TextEncodingFormat		textEncodingFormat;
	
	///////
        PsychWindowRecordType           *winRec;
	char				*textCString;
	Str255				textPString;
	UniChar				*textUniString;
	OSStatus			callError;
	PsychRectType			resultPsychRect, resultPsychNormRect;
	ATSUTextLayout			textLayout;				//layout is a pointer to an opaque struct.
	int				stringLengthChars;
	int				uniCharBufferLengthElements, uniCharBufferLengthChars, uniCharBufferLengthBytes, yPositionIsBaseline;
	double			textHeightToBaseline;
	ByteCount			uniCharStringLengthBytes;
	TextToUnicodeInfo		textToUnicodeInfo;
	TextEncoding			textEncoding;
	ATSUStyle			atsuStyle;
	Boolean				foundFont;
	
	//for ATSU  style attributes
	PsychFontStructPtrType  psychFontRecord;

    			
        //all subfunctions should have these two lines.  
        PsychPushHelp(useString, synopsisString, seeAlsoString);
        if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
        //check for correct the number of arguments before getting involved
        PsychErrorExit(PsychCapNumInputArgs(5));   	
        PsychErrorExit(PsychRequireNumInputArgs(2)); 	
        PsychErrorExit(PsychCapNumOutputArgs(2));
	
	//get the window pointer and the text string and check that the window record has a font set
        PsychAllocInWindowRecordArg(1, kPsychArgRequired, &winRec);
	foundFont=PsychGetFontRecordFromFontNumber(winRec->textAttributes.textFontNumber, &psychFontRecord);
	if(!foundFont)
		PsychErrorExitMsg(PsychError_user, "Attempt to determine the bounds of text with no font or invalid font number");
		//it would be better to both prevent the user from setting invalid font numbers and init to the OS 9  default font.
	
	//read in the string and get its length and convert it to a unicode string.
	PsychAllocInCharArg(2, kPsychArgRequired, &textCString);
	stringLengthChars=strlen(textCString);
	if(stringLengthChars < 1) PsychErrorExitMsg(PsychError_user, "You asked me to compute the bounding box of an empty text string?!? Sorry, that's a no no...");
	if(stringLengthChars > 255) PsychErrorExitMsg(PsychError_unimplemented, "Cut corners and TextBounds will not accept a string longer than 255 characters");
	CopyCStringToPascal(textCString, textPString);
	uniCharBufferLengthChars= stringLengthChars * CHAR_TO_UNICODE_LENGTH_FACTOR;
	uniCharBufferLengthElements= uniCharBufferLengthChars + 1;		
	uniCharBufferLengthBytes= sizeof(UniChar) * uniCharBufferLengthElements;
	textUniString=(UniChar*)malloc(uniCharBufferLengthBytes);

    PsychCopyInDoubleArg(3, kPsychArgOptional, &(winRec->textAttributes.textPositionX));
    PsychCopyInDoubleArg(4, kPsychArgOptional, &(winRec->textAttributes.textPositionY));

	//Using a TextEncoding type describe the encoding of the text to be converteed.  
	textEncoding=CreateTextEncoding(kTextEncodingMacRoman, kMacRomanDefaultVariant, kTextEncodingDefaultFormat);
	//Take apart the encoding we just made to check it:
        textEncodingBase=GetTextEncodingBase(textEncoding);
        textEncodingVariant=GetTextEncodingVariant(textEncoding);
        textEncodingFormat=GetTextEncodingFormat(textEncoding);
	//Create a structure holding conversion information from the text encoding type we just created.
	callError=CreateTextToUnicodeInfoByEncoding(textEncoding,&textToUnicodeInfo);
	//Convert the text to a unicode string
	callError=ConvertFromPStringToUnicode(textToUnicodeInfo, textPString, (ByteCount)uniCharBufferLengthBytes,	&uniCharStringLengthBytes,	textUniString);
	//create the text layout object
	callError=ATSUCreateTextLayout(&textLayout);			
	//associate our unicode text string with the text layout object
	callError=ATSUSetTextPointerLocation(textLayout, textUniString, kATSUFromTextBeginning, kATSUToTextEnd, (UniCharCount)stringLengthChars);
	
	//create an ATSU style object
	callError=ATSUCreateStyle(&atsuStyle);
	callError=ATSUClearStyle(atsuStyle);
	
	//Not that we have a style object we have to set style charactersitics.  These include but are more general than Font Manager styles.  
	//ATSU Style objects have three sets of characteristics:  attributes, variations, and features.
	//attributes are things we need to set to match OS 9 behavior, such as the font ID, size, boldness, and italicization.
	//features are esoteric settings which we don't need for reproducing OS 9 behavior.  Whatever clearstyle sets should be fine.
	//font variations are axes of variation through the space of font characteristics.  The font definition includes available axes of variation.  Something else we can ignore for now.  
	PsychSetATSUStyleAttributesFromPsychWindowRecord(atsuStyle, winRec);
	//don't bother to set the variations of the style.
	//don't bother to set the features of the style.
	
	//associate the style with our layout object. This call assigns a style to every character of the string to be displayed.  
	callError=ATSUSetRunStyle(textLayout, atsuStyle, (UniCharArrayOffset)0, (UniCharCount)stringLengthChars);

	// Define the meaning of the y position of the specified drawing cursor.
	// We get the global setting from the Screen preference, but allow to override
	// it on a per-invocation basis via the optional 7th argument to 'DrawText':
	yPositionIsBaseline = PsychPrefStateGet_TextYPositionIsBaseline();
	PsychCopyInIntegerArg(5, kPsychArgOptional, &yPositionIsBaseline);
	 
	if (yPositionIsBaseline) {
		// Y position of drawing cursor defines distance between top of text and
		// baseline of text, i.e. the textheight excluding descenders of letters:

		// Need to compute offset via ATSU:
		ATSUTextMeasurement mleft, mright, mtop, mbottom;
        callError=ATSUGetUnjustifiedBounds(textLayout, kATSUFromTextBeginning, kATSUToTextEnd, &mleft, &mright, &mbottom, &mtop);
		if (callError) {
			PsychErrorExitMsg(PsychError_internal, "Failed to compute unjustified text height to baseline in call to ATSUGetUnjustifiedBounds().\n");    
		}

		// Only take height including ascenders into account, not the descenders.
		// MK: Honestly, i have no clue why this is the correct calculation (or if it is
		// the correct calculation), but visually it seems to provide the correct results
		// and i'm not a typographic expert and don't intend to become one...
		textHeightToBaseline = fabs(Fix2X(mbottom));
	}
	else {
		// Y position of drawing cursor defines top of text, therefore no offset (==0) needed:
		textHeightToBaseline = 0;
	}

	//Get the bounds for our text so that and create a texture of sufficient size to containt it. 
	ATSTrapezoid trapezoid;
	ItemCount oActualNumberOfBounds = 0;
	callError=ATSUGetGlyphBounds(textLayout, 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 0, NULL, &oActualNumberOfBounds);
	if (callError || oActualNumberOfBounds!=1) {
		PsychErrorExitMsg(PsychError_internal, "Failed to compute bounding box in call 1 to ATSUGetGlyphBounds() (nrbounds!=1)\n");    
	}
	callError=ATSUGetGlyphBounds(textLayout, 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 1, &trapezoid, &oActualNumberOfBounds);
	if (callError || oActualNumberOfBounds!=1) {
		PsychErrorExitMsg(PsychError_internal, "Failed to retrieve bounding box in call 2 to ATSUGetGlyphBounds() (nrbounds!=1)\n");    
	}
	
	resultPsychRect[kPsychLeft]=(Fix2X(trapezoid.upperLeft.x) < Fix2X(trapezoid.lowerLeft.x)) ? Fix2X(trapezoid.upperLeft.x) : Fix2X(trapezoid.lowerLeft.x);
	resultPsychRect[kPsychRight]=(Fix2X(trapezoid.upperRight.x) > Fix2X(trapezoid.lowerRight.x)) ? Fix2X(trapezoid.upperRight.x) : Fix2X(trapezoid.lowerRight.x);
	resultPsychRect[kPsychTop]=(Fix2X(trapezoid.upperLeft.y) < Fix2X(trapezoid.upperRight.y)) ? Fix2X(trapezoid.upperLeft.y) : Fix2X(trapezoid.upperRight.y);
	resultPsychRect[kPsychBottom]=(Fix2X(trapezoid.lowerLeft.y) > Fix2X(trapezoid.lowerRight.y)) ? Fix2X(trapezoid.lowerLeft.y) : Fix2X(trapezoid.lowerRight.y);
	
	PsychNormalizeRect(resultPsychRect, resultPsychNormRect);
	resultPsychRect[kPsychLeft]=resultPsychNormRect[kPsychLeft] + winRec->textAttributes.textPositionX;
	resultPsychRect[kPsychRight]=resultPsychNormRect[kPsychRight] + winRec->textAttributes.textPositionX;
	resultPsychRect[kPsychTop]=resultPsychNormRect[kPsychTop] + winRec->textAttributes.textPositionY - textHeightToBaseline;
	resultPsychRect[kPsychBottom]=resultPsychNormRect[kPsychBottom] + winRec->textAttributes.textPositionY - textHeightToBaseline;

	PsychCopyOutRectArg(1, FALSE, resultPsychNormRect);
	PsychCopyOutRectArg(2, FALSE, resultPsychRect);


	//release resources
	free((void*)textUniString);
	callError=ATSUDisposeStyle(atsuStyle);

    return(PsychError_none);
}
PsychError SCREENNull(void) 

{

	const double defaultMatrix[] = {1.1, 1.2, 1.3, 1.4, 2.1, 2.2, 2.3, 2.4};

	const double defaultM=2, defaultN=4; 

	double tempValue; 

	double *array;

	int i, m,n, p, numInArgs, numOutArgs, numNamedOutArgs;

	char *str;

	PsychArgFormatType format;

	const char defaultString[] = "I am the default string\n";

	





	//all sub functions should have these two lines

	PsychPushHelp(useString, synopsisString, seeAlsoString);

	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};



	//demonstrate how we find the function and subfunction names

	//printf("Psychtoolbox function: %s, subfunction %s\n", PsychGetModuleName(), PsychGetFunctionName() );



	//copy all the input argument to their outputs if we have doubles, if not error.  

	numInArgs = PsychGetNumInputArgs();

	numOutArgs = PsychGetNumOutputArgs();

	numNamedOutArgs = PsychGetNumNamedOutputArgs();

	

	PsychErrorExit(PsychCapNumOutputArgs(numInArgs));

	

	

	/*

	printf("number of input arguments: %d\n", numInArgs);

	printf("number of output arguments: %d\n", numOutArgs);

	printf("number of named output arguments: %d\n", numNamedOutArgs);

	*/

	

		

	

	//iterate over each of the supplied inputs.  If the input is a two-dimensional array 

	//of doubles or a character array, then copy it to the output.  

	for(i=1;i<=numInArgs;i++){

		format = PsychGetArgType(i);

		switch(format){

			case PsychArgType_double:

				if(PsychGetArgM(i)==1 && PsychGetArgN(i)==1){

					tempValue=i;  //if 1x1 double then the default return value is the arg position.

					PsychCopyInDoubleArg(i, FALSE, &tempValue);

					PsychCopyOutDoubleArg(i, FALSE, tempValue);

				}else{

					PsychAllocInDoubleMatArg(i, FALSE, &m, &n, &p, &array);

					PsychCopyOutDoubleMatArg(i, FALSE, m, n, p, array);

				}

				break;

			case PsychArgType_char:

				str=NULL; //This tells PsychGetCharArg() to use its own (volatile) memory. 

				PsychAllocInCharArg(i, FALSE, &str); 

				PsychCopyOutCharArg(i, FALSE, str);

				break;

			case PsychArgType_default:

				PsychCopyOutCharArg(i, FALSE, defaultString);

				break;

		}

	}

		

	return(PsychError_none);

}
PsychError SCREENOpenMovie(void)
{
    PsychWindowRecordType                   *windowRecord;
    char                                    *moviefile;
    char                                    *movieOptions;
    char                                    dummmyOptions[1];
    int                                     moviehandle = -1;
    int                                     framecount;
    double                                  durationsecs;
    double                                  framerate;
    double                                  aspectRatio;
    int                                     width;
    int                                     height;
    int                                     asyncFlag = 0;
    int                                     specialFlags1 = 0;
    static psych_bool                       firstTime = TRUE;
    double                                  preloadSecs = 1;
    int                                     rc;
    int                                     pixelFormat = 4;
    int                                     maxNumberThreads = -1;

    if (firstTime) {
        // Setup asyncopeninfo on first invocation:
        firstTime = FALSE;
        asyncmovieinfo.asyncstate = 0; // State = No async open in progress.
    }

    // All sub functions should have these two lines
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none);};

    PsychErrorExit(PsychCapNumInputArgs(8));            // Max. 8 input args.
    PsychErrorExit(PsychRequireNumInputArgs(1));        // Min. 1 input args required.
    PsychErrorExit(PsychCapNumOutputArgs(7));           // Max. 7 output args.

    // Get the window record from the window record argument and get info from the window record
    windowRecord = NULL;
    PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, FALSE, &windowRecord);

    // Only onscreen windows allowed:
    if(windowRecord && !PsychIsOnscreenWindow(windowRecord)) {
        PsychErrorExitMsg(PsychError_user, "OpenMovie called on something else than an onscreen window.");
    }

    // Get the movie name string:
    moviefile = NULL;
    PsychAllocInCharArg(2, kPsychArgRequired, &moviefile);

    // Get the (optional) asyncFlag:
    PsychCopyInIntegerArg(3, FALSE, &asyncFlag);

    PsychCopyInDoubleArg(4, FALSE, &preloadSecs);
    if (preloadSecs < 0 && preloadSecs!= -1 && preloadSecs!= -2) PsychErrorExitMsg(PsychError_user, "OpenMovie called with invalid (negative, but not equal -1) 'preloadSecs' argument!");

    // Get the (optional) specialFlags1:
    PsychCopyInIntegerArg(5, FALSE, &specialFlags1);
    if (specialFlags1 < 0) PsychErrorExitMsg(PsychError_user, "OpenMovie called with invalid 'specialFlags1' setting! Only positive values allowed.");

    // Get the (optional) pixelFormat:
    PsychCopyInIntegerArg(6, FALSE, &pixelFormat);
    if (pixelFormat < 1 || pixelFormat > 10) PsychErrorExitMsg(PsychError_user, "OpenMovie called with invalid 'pixelFormat' setting! Only values 1 to 10 are allowed.");

    // Get the (optional) maxNumberThreads:
    PsychCopyInIntegerArg(7, FALSE, &maxNumberThreads);
    if (maxNumberThreads < -1) PsychErrorExitMsg(PsychError_user, "OpenMovie called with invalid 'maxNumberThreads' setting! Only values of -1 or greater are allowed.");

    // Get the (optional) movie options string: As PsychAllocInCharArg() no-ops if
    // the optional string isn't provided, we need to point movieOptions to an empty
    // 0-terminated string by default, so we don't have a dangling pointer:
    dummmyOptions[0] = 0;
    movieOptions = &dummmyOptions[0];
    PsychAllocInCharArg(8, FALSE, &movieOptions);

    // Queueing of a new movie for seamless playback requested?
    if (asyncFlag & 2) {
        // Yes. Do a special call, just passing the moviename of the next
        // movie to play. Pass the relevant moviehandle as retrieved from
        // preloadSecs:
        moviehandle = (int) preloadSecs;
        preloadSecs = 0;
        PsychCreateMovie(windowRecord, moviefile, preloadSecs, &moviehandle, asyncFlag, specialFlags1, pixelFormat, maxNumberThreads, movieOptions);
        if (moviehandle == -1) PsychErrorExitMsg(PsychError_user, "Could not queue new moviefile for gapless playback.");
        return(PsychError_none);
    }

    // Asynchronous Open operation in progress or requested?
    if ((asyncmovieinfo.asyncstate == 0) && !(asyncFlag & 1)) {
        // No. We should just synchronously open the movie:

        // Try to open the named 'moviefile' and create & initialize a corresponding movie object.
        // A handle to the movie object is returned upon successfull operation.
        PsychCreateMovie(windowRecord, moviefile, preloadSecs, &moviehandle, asyncFlag, specialFlags1, pixelFormat, maxNumberThreads, movieOptions);
    }
    else {
        // Asynchronous open operation requested or running:
        switch(asyncmovieinfo.asyncstate) {
            case 0: // No async open running, but async open requested
                // Fill all information needed for opening the movie into the info struct:
                asyncmovieinfo.asyncstate = 1; // Mark state as "Operation in progress"
                asyncmovieinfo.moviename = strdup(moviefile);
                asyncmovieinfo.preloadSecs = preloadSecs;
                asyncmovieinfo.asyncFlag = asyncFlag;
                asyncmovieinfo.specialFlags1 = specialFlags1;
                asyncmovieinfo.pixelFormat = pixelFormat;
                asyncmovieinfo.maxNumberThreads = maxNumberThreads;
                asyncmovieinfo.movieOptions = strdup(movieOptions);

                if (windowRecord) {
                    memcpy(&asyncmovieinfo.windowRecord, windowRecord, sizeof(PsychWindowRecordType));
                } else {
                    memset(&asyncmovieinfo.windowRecord, 0, sizeof(PsychWindowRecordType));
                }

                asyncmovieinfo.moviehandle = -1;

                // Increase our scheduling priority to basic RT priority: This way we should get
                // more cpu time for our PTB main thread than the async. background prefetch-thread:
                // On Windows we must not go higher than basePriority 1 (HIGH PRIORITY) or bad interference can happen.
                // On OS/X we use basePriority 2 for robust realtime, using up to (4+1) == 5 msecs of time in every 10 msecs slice, allowing for up to 1 msec jitter/latency for ops.
                // On Linux we just use standard basePriority 2 RT-FIFO scheduling and trust the os to do the right thing.
                if ((rc=PsychSetThreadPriority(NULL, ((PSYCH_SYSTEM == PSYCH_WINDOWS) ? 1 : 2), ((PSYCH_SYSTEM == PSYCH_OSX) ? 4 : 0)))!=0) {
                    printf("PTB-WARNING: In OpenMovie(): Failed to raise priority of main thread [System error %i]. Expect movie timing problems.\n", rc);
                }

                // Start our own movie loader Posix-Thread:
                PsychCreateThread(&asyncmovieinfo.pid, NULL, PsychAsyncCreateMovie, &asyncmovieinfo);

                // Async movie open initiated. We return control to host environment:
                return(PsychError_none);
            break;

            case 1: // Async open operation in progress, but not yet finished.
                // Should we wait for completion or just return?
                if (asyncFlag & 1) {
                    // Async poll requested. We just return -1 to signal that open isn't finished yet:
                    PsychCopyOutDoubleArg(1, TRUE, -1);
                    return(PsychError_none);
                }
                // We fall through to case 2 - Wait for "Load operation successfully finished."
                // Fall through.
            case 2: // Async open operation finished. Parse asyncinfo struct and return it to host environment:
                // We need to join our terminated worker thread to release its ressources. If the worker-thread
                // isn't done yet (fallthrough from case 1 for sync. wait), this join will block us until worker
                // completes:
                PsychDeleteThread(&asyncmovieinfo.pid);

                asyncmovieinfo.asyncstate = 0; // Reset state to idle:
                moviehandle = asyncmovieinfo.moviehandle;

                // Release options string:
                free(asyncmovieinfo.movieOptions);

                // Movie successfully opened?
                if (moviehandle < 0) {
                    // Movie loading failed for some reason.
                    printf("PTB-ERROR: When trying to asynchronously load movie '%s', the operation failed! Reasons given above.\n", asyncmovieinfo.moviename);
                    free(asyncmovieinfo.moviename);
                    PsychErrorExitMsg(PsychError_user, "Asynchronous loading of the movie failed.");
                }

                free(asyncmovieinfo.moviename);

                // We can fall out of the switch statement and continue with the standard synchronous load code as if
                // the movie had been loaded synchronously.
            break;
            default:
                PsychErrorExitMsg(PsychError_internal, "Unhandled async movie state condition encountered! BUG!!");
        }
    }

    // Upon sucessfull completion, we'll have a valid handle in 'moviehandle'.
    PsychCopyOutDoubleArg(1, TRUE, (double) moviehandle);

    // Retrieve infos about new movie:

    // Is the "count" output argument (total number of frames) requested by user?
    if (PsychGetNumOutputArgs() > 5) {
        // Yes. Query the framecount (expensive!) and return it:
        PsychGetMovieInfos(moviehandle, &width, &height, &framecount, &durationsecs, &framerate, NULL, &aspectRatio);
        PsychCopyOutDoubleArg(6, TRUE, (double) framecount);
    }
    else {
        // No. Don't compute and return it.
        PsychGetMovieInfos(moviehandle, &width, &height, NULL, &durationsecs, &framerate, NULL, &aspectRatio);
    }

    PsychCopyOutDoubleArg(2, FALSE, (double) durationsecs);
    PsychCopyOutDoubleArg(3, FALSE, (double) framerate);
    PsychCopyOutDoubleArg(4, FALSE, (double) width);
    PsychCopyOutDoubleArg(5, FALSE, (double) height);
    PsychCopyOutDoubleArg(7, FALSE, (double) aspectRatio);

    // Ready!
    return(PsychError_none);
}
PsychError SCREENBlendFunction(void)
{
	PsychWindowRecordType 	*windowRecord;
	GLenum					oldSource, oldDestination, newSource, newDestination;
	char					*oldSoureStr, *oldDestinationStr, *newSourceStr, *newDestinationStr;
	int						oldSourceStrSize, oldDestinationStrSize, isSourceStringValid, isDestinationStringValid;
	psych_bool					isSourceSupplied, isDestinationSupplied, isSourceChoiceValid, isDestinationChoiceValid;
	double					*oldColorMask, *newColorMask;
	int						m, n, p;
	
	//all subfunctions should have these two lines.  
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

	PsychErrorExit(PsychCapNumInputArgs(4));		//The maximum number of inputs
	PsychErrorExit(PsychRequireNumInputArgs(1));	//The required number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(3));		//The maximum number of outputs

	//Get the window record or exit with an error if the windex was bogus.
	PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);

	//Retreive the old source and destination factors and return them from the Screen call as strings
	PsychGetAlphaBlendingFactorsFromWindow(windowRecord, &oldSource, &oldDestination);

	oldSourceStrSize=PsychGetAlphaBlendingFactorStringFromConstant(oldSource, NULL);
	oldDestinationStrSize=PsychGetAlphaBlendingFactorStringFromConstant(oldDestination, NULL);
	
	oldSoureStr=(char *)malloc(sizeof(char) * oldSourceStrSize);
	oldDestinationStr=(char *)malloc(sizeof(char) * oldDestinationStrSize);

	PsychGetAlphaBlendingFactorStringFromConstant(oldSource, oldSoureStr);
	PsychGetAlphaBlendingFactorStringFromConstant(oldDestination, oldDestinationStr);

	PsychCopyOutCharArg(1, kPsychArgOptional, oldSoureStr);
	PsychCopyOutCharArg(2, kPsychArgOptional, oldDestinationStr);
	
	free((void *)oldSoureStr);
	free((void *)oldDestinationStr);

	//Get the new settings if they are present and set them.
	newSource=oldSource;
	newDestination=oldDestination;

	isSourceSupplied= PsychAllocInCharArg(2, kPsychArgOptional, &newSourceStr);
	isDestinationSupplied= PsychAllocInCharArg(3, kPsychArgOptional, &newDestinationStr);

	if(isSourceSupplied){
		isSourceStringValid=PsychGetAlphaBlendingFactorConstantFromString(newSourceStr, &newSource);
		if(!isSourceStringValid) PsychErrorExitMsg(PsychError_user, "Supplied string argument 'sourceFactorNew' is invalid");

		isSourceChoiceValid=PsychValidateBlendingConstantForSource(newSource);
		if(!isSourceChoiceValid) PsychErrorExitMsg(PsychError_user, "The blending factor supplied for the source is only valid only for the destination");
	}

	if(isDestinationSupplied){
		isDestinationStringValid=PsychGetAlphaBlendingFactorConstantFromString(newDestinationStr, &newDestination);
		if(!isDestinationStringValid) PsychErrorExitMsg(PsychError_user, "Supplied string argument 'destinationFactorNew' is invalid");

		isDestinationChoiceValid=PsychValidateBlendingConstantForDestination(newDestination);
		if(!isDestinationChoiceValid) PsychErrorExitMsg(PsychError_user, "The blending factor supplied for the destination is only valid only for the source");
	}

	PsychStoreAlphaBlendingFactorsForWindow(windowRecord, newSource, newDestination);

	// Check if alpha blending is possible for this windowRecord:
	if ((newSource != GL_ONE || newDestination != GL_ZERO) && !((windowRecord->bpc < 16) || (windowRecord->bpc == 16 && (windowRecord->gfxcaps & kPsychGfxCapFPBlend16)) || (windowRecord->bpc == 32 && (windowRecord->gfxcaps & kPsychGfxCapFPBlend32)))) {
		// Nope. Alpha blending requested but not possible for this windowRecord with this gfx-hardware.
		if (PsychPrefStateGet_Verbosity() > 1) {
			printf("PTB-WARNING: Screen('Blendfunction') called to enable alpha-blending on a window (handle=%i) which doesn't support\n", windowRecord->windowIndex);
			printf("PTB-WARNING: alpha-blending at its current color resolution of %i bits per color component on your hardware.\n", windowRecord->bpc);
			printf("PTB-WARNING: Won't enable blending. Either lower the color resolution of the window (see help PsychImaging) or\n");
			printf("PTB-WARNING: upgrade your graphics hardware.\n\n");
		}
	}
	
	// Create return array with encoded old colormask:
	PsychAllocOutDoubleMatArg(3, kPsychArgOptional, 1, 4, 1, &oldColorMask);
	oldColorMask[0] = (windowRecord->colorMask[0]) ? 1 : 0;
	oldColorMask[1] = (windowRecord->colorMask[1]) ? 1 : 0;
	oldColorMask[2] = (windowRecord->colorMask[2]) ? 1 : 0;
	oldColorMask[3] = (windowRecord->colorMask[3]) ? 1 : 0;

	// Any new colormask provided?
	if (PsychAllocInDoubleMatArg(4, kPsychArgOptional, &m, &n, &p, &newColorMask)) {
		// Yes. Assign it:
		if (p!=1 || m*n != 4)  PsychErrorExitMsg(PsychError_user, "The colorMaskNew argument must be a 4 element row- or column vector!");

		windowRecord->colorMask[0] = (newColorMask[0] > 0) ? GL_TRUE : GL_FALSE;
		windowRecord->colorMask[1] = (newColorMask[1] > 0) ? GL_TRUE : GL_FALSE;
		windowRecord->colorMask[2] = (newColorMask[2] > 0) ? GL_TRUE : GL_FALSE;
		windowRecord->colorMask[3] = (newColorMask[3] > 0) ? GL_TRUE : GL_FALSE;
	}
	
	return(PsychError_none);
}
PsychError SCREENTextFont(void) 
{
    psych_bool			doSetByName, doSetByNumber, foundFont;
    PsychWindowRecordType	*windowRecord;
#if PSYCH_SYSTEM == PSYCH_OSX
    PsychFontStructType		*fontRecord;
#endif
    int				oldTextFontNumber, inputTextFontNumber;
    char			*oldTextFontName, *inputTextFontName;
    int             oldTextStyle, newTextStyle;
    
    //all subfunctions should have these two lines.  
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    //check for valid number of arguments
    PsychErrorExit(PsychRequireNumInputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(3));
    PsychErrorExit(PsychCapNumOutputArgs(3));
    
    //Get the window record
    PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
    
    //Save the old text font value and return it.
    oldTextFontNumber=windowRecord->textAttributes.textFontNumber;
    PsychCopyOutDoubleArg(2, FALSE, (double)oldTextFontNumber);
    oldTextFontName=(char*) windowRecord->textAttributes.textFontName;
    PsychCopyOutCharArg(1, FALSE, oldTextFontName);
    oldTextStyle = windowRecord->textAttributes.textStyle;
    PsychCopyOutDoubleArg(3, FALSE, (double) oldTextStyle);
	
    //Fetch and set the new font if specified by name or number
    PsychCheckInputArgType(2, kPsychArgOptional, PsychArgType_double | PsychArgType_char);  //if the argument is there check that it is the right type.
    doSetByNumber= PsychCopyInIntegerArg(2, kPsychArgAnything, &inputTextFontNumber);
    doSetByName= PsychAllocInCharArg(2, kPsychArgAnything, &inputTextFontName);
    foundFont=0;
#if PSYCH_SYSTEM == PSYCH_OSX
    if(doSetByNumber) {
        foundFont=PsychGetFontRecordFromFontNumber(inputTextFontNumber, &fontRecord);
    }
    
    if(doSetByName) {
        if (PsychCopyInIntegerArg(3, FALSE, &newTextStyle)) windowRecord->textAttributes.textStyle = newTextStyle;
        foundFont=PsychGetFontRecordFromFontFamilyNameAndFontStyle(inputTextFontName, windowRecord->textAttributes.textStyle, &fontRecord);
    }
    
    if(foundFont) {
        strncpy((char*) windowRecord->textAttributes.textFontName, (char*) fontRecord->fontFMFamilyName, 255);
        windowRecord->textAttributes.textFontNumber = fontRecord->fontNumber;
        windowRecord->textAttributes.textStyle = fontRecord->fontFMStyle;
    }
	else {
		// Font not found. Is this textrenderer 2 with a font given by name?
		if (doSetByName && (PsychPrefStateGet_TextRenderer() > 1)) {
			// Yes: Must be a special font specifier string for the renderer plugin. Just assign it directly:
			strncpy((char*) windowRecord->textAttributes.textFontName, inputTextFontName, 255);

			// Don't have a valid fontNumber: Just assign a zero...
			windowRecord->textAttributes.textFontNumber = 0;
		}
        else {
            // Restore old text style setting:
            windowRecord->textAttributes.textStyle = oldTextStyle;
        }
	}
    
    return(PsychError_none);
#else
    // Special case for MS-Windows and Linux:
    if(doSetByNumber) printf("PTB-WARNING: Sorry, selecting font by number in Screen('TextFont') is not yet supported on Windows or Linux. Command ignored.\n");
    if(doSetByName && (strncmp(windowRecord->textAttributes.textFontName, inputTextFontName, 255 )!=0)) {
      strncpy(windowRecord->textAttributes.textFontName, inputTextFontName, 255);
      windowRecord->textAttributes.textFontNumber= 0;
      // Set the rebuild flag:
      windowRecord->textAttributes.needsRebuild=TRUE;
    }
    
    // New and different text style provided?
    if (PsychCopyInIntegerArg(3, FALSE, &newTextStyle) && (windowRecord->textAttributes.textStyle != newTextStyle)) {
        windowRecord->textAttributes.textStyle = newTextStyle;
        // Set the rebuild flag:
        windowRecord->textAttributes.needsRebuild=TRUE;
    }

    return(PsychError_none);
#endif
}
PsychError SCREENPreference(void)  
{

	PsychArgFormatType		arg1Type;
	char					*preferenceName, *newFontName;
	const char				*tableCreator, *oldDefaultFontName;
	Boolean					preferenceNameArgumentValid, booleanInput, ignoreCase, tempFlag, textAlphaBlendingFlag, suppressAllWarningsFlag;
	int						numInputArgs, i, newFontStyleNumber, newFontSize, tempInt, tempInt2, tempInt3;
	double					returnDoubleValue, inputDoubleValue;
	
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous or missing arguments
	PsychErrorExit(PsychCapNumInputArgs(3));			
	PsychErrorExit(PsychRequireNumInputArgs(1));		   
	PsychErrorExit(PsychCapNumOutputArgs(1));
	
	numInputArgs=PsychGetNumInputArgs();
	arg1Type=PsychGetArgType(1);
	preferenceNameArgumentValid=FALSE;
	
	//Cases which require both a window pointer or screen number and preference name.  Argument 1 is the wposn and argument 2 is the preference name.
	if( numInputArgs >= 2 && (PsychIsScreenNumberArg(1) || PsychIsScreenNumberArg(1)) && PsychGetArgType(2)==PsychArgType_char ){
		PsychAllocInCharArg(2, kPsychArgRequired, &preferenceName);
		//preferences which require window pointer or screen number argument which we DO NOT support  
		for(i=0;i<kPsychNumUnsupportedMacVideoPreferences;i++){
			if(PsychMatch(preferenceName, unsupportedMacVideoPreferenceNames[i]))
				PsychErrorExit(PsychError_unsupportedOS9Preference);
		}
		//insert here conditionals  to act on prefernces which accept a window pointer or screen number argument which we DO support.
		PsychErrorExit(PsychError_unrecognizedPreferenceName);
	}

	//Cases which do not require a wposn.  Argument 1 is the preference name.  if present Argument 2 is the new value
	if(arg1Type==PsychArgType_char){
		PsychAllocInCharArg(1, kPsychArgRequired, &preferenceName);
		//Preferernces which we do not support and which do not require a wposn
		for(i=0;i<kPsychNumUnsupportedMacNonVideoPreferences;i++){
			if(PsychMatch(preferenceName, unsupportedMacNonVideoPreferenceNames[i]))
				PsychErrorExit(PsychError_unsupportedOS9Preference);
		}
		//Preferences which we do support
		if(PsychMatch(preferenceName, "IgnoreCase")){
			ignoreCase=!PsychIsPsychMatchCaseSensitive();
			PsychCopyOutFlagArg(1, kPsychArgOptional, ignoreCase);
			if(numInputArgs==2){
				PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
				PsychSetPsychMatchCaseSenstive(!booleanInput);			
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "Tick0Secs")){
			if(PsychCopyInDoubleArg(2, kPsychArgOptional, &inputDoubleValue) && inputDoubleValue==PsychGetNanValue())
				PsychEstimateGetSecsValueAtTickCountZero();
			returnDoubleValue=PsychGetEstimatedSecsValueAtTickCountZero();
			PsychCopyOutDoubleArg(1, kPsychArgOptional, returnDoubleValue);
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "PsychTableVersion")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)PsychPrefStateGet_PsychTableVersion());
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "PsychTableCreator")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			tableCreator=PsychPrefStateGet_PsychTableCreator();
			PsychCopyOutCharArg(1, kPsychArgOptional, tableCreator);
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "Process")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)getpid());
			preferenceNameArgumentValid=TRUE;


		}else 
		if(PsychMatch(preferenceName, "DefaultFontName")){
			PsychPrefStateGet_DefaultFontName(&oldDefaultFontName);
			PsychCopyOutCharArg(1, kPsychArgOptional, oldDefaultFontName);
			if(numInputArgs==2){
				PsychAllocInCharArg(2, kPsychArgRequired, &newFontName);
				PsychPrefStateSet_DefaultFontName(newFontName);
			}
			preferenceNameArgumentValid=TRUE;
			
		}else 
		if(PsychMatch(preferenceName, "DefaultFontStyle")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DefaultTextStyle());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &newFontStyleNumber);
				PsychPrefStateSet_DefaultTextStyle(newFontStyleNumber);
			}
			preferenceNameArgumentValid=TRUE;
		}else
		if(PsychMatch(preferenceName, "DefaultTextYPositionIsBaseline")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_TextYPositionIsBaseline());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_TextYPositionIsBaseline(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "TextAntiAliasing")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_TextAntiAliasing());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_TextAntiAliasing(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "TextRenderer")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_TextRenderer());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_TextRenderer(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "DefaultFontSize")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DefaultTextSize());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &newFontSize);
				PsychPrefStateSet_DefaultTextSize(newFontSize);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "DebugMakeTexture")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DebugMakeTexture());
			if(numInputArgs==2){
				PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
				PsychPrefStateSet_DebugMakeTexture(tempFlag);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SkipSyncTests")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_SkipSyncTests());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_SkipSyncTests(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VisualDebugLevel")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VisualDebugLevel());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_VisualDebugLevel(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VBLTimestampingMode")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VBLTimestampingMode());
			if(numInputArgs>=2){
                            PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
                            PsychPrefStateSet_VBLTimestampingMode(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VBLEndlineOverride")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VBLEndlineOverride());
			if(numInputArgs>=2){
                            PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
                            PsychPrefStateSet_VBLEndlineOverride(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else
			if(PsychMatch(preferenceName, "DefaultVideocaptureEngine")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VideoCaptureEngine());
				if(numInputArgs==2){
					PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
					PsychPrefStateSet_VideoCaptureEngine(tempInt);
				}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "ConserveVRAM") || PsychMatch(preferenceName, "Workarounds1")){
					PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_ConserveVRAM());
					if(numInputArgs==2){
						PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
						PsychPrefStateSet_ConserveVRAM(tempInt);
					}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "Verbosity")){
					PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_Verbosity());
					if(numInputArgs==2){
						PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
						PsychPrefStateSet_Verbosity(tempInt);
					}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "EmulateOldPTB")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_EmulateOldPTB());
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
					PsychPrefStateSet_EmulateOldPTB(tempFlag);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "Enable3DGraphics")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_3DGfx());
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
					PsychPrefStateSet_3DGfx(tempFlag);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "TextAlphaBlending")){
				textAlphaBlendingFlag=PsychPrefStateGet_TextAlphaBlending();
				PsychCopyOutFlagArg(1, kPsychArgOptional, textAlphaBlendingFlag);
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
					PsychPrefStateSet_TextAlphaBlending(booleanInput);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SuppressAllWarnings")){
				suppressAllWarningsFlag=PsychPrefStateGet_SuppressAllWarnings();
				PsychCopyOutFlagArg(1, kPsychArgOptional, suppressAllWarningsFlag);
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
					PsychPrefStateSet_SuppressAllWarnings(booleanInput);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SynchronizeDisplays")){
				if(numInputArgs==2){
					// This is a special call: It currently doesn't set a preference setting,
					// but instead triggers an instantaneous synchronization of all available
					// display heads, if possible. We may have a more clever and "standard" interface
					// interface for this later on, but for first tests this will do.
					// Syncmethod is hard-coded to 0 -> Use whatever's available to sync.
					// timeout for retries is 5.0 seconds.
					// Acceptable residual offset is +/- 2 scanlines.
					// Returns the real residual offset after sync.
					PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
					tempInt2 = 0;
					if (PsychSynchronizeDisplayScreens(&tempInt2, NULL, &tempInt, tempInt, 5.0, 2)!=PsychError_none) PsychErrorExitMsg(PsychError_user, "Sync failed for reasons mentioned above.");
					PsychCopyOutDoubleArg(1, kPsychArgOptional, tempInt);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			PsychErrorExit(PsychError_unrecognizedPreferenceName);
	}
	
	if(!preferenceNameArgumentValid)
		PsychErrorExitMsg(PsychError_user, "Invalid arguments to preferences command");
		
	return(PsychError_none);
}
// This also works as 'AddFrameToMovie', as almost all code is shared with 'GetImage'.
// Only difference is where the fetched pixeldata is sent: To the movie encoder or to
// a matlab/octave matrix.
PsychError SCREENGetImage(void) 
{
	PsychRectType   windowRect, sampleRect;
	int 			nrchannels, invertedY, stride;
	size_t			ix, iy, sampleRectWidth, sampleRectHeight, redReturnIndex, greenReturnIndex, blueReturnIndex, alphaReturnIndex, planeSize;
	int				viewid = 0;
	psych_uint8 	*returnArrayBase, *redPlane;
	float 			*dredPlane;
	double 			*returnArrayBaseDouble;
	PsychWindowRecordType	*windowRecord;
	GLboolean		isDoubleBuffer, isStereo;
	char*           buffername = NULL;
	psych_bool		floatprecision = FALSE;
	GLenum			whichBuffer = 0; 
	int				frameduration = 1;
	int				moviehandle = 0;
	unsigned int	twidth, theight, numChannels, bitdepth;
	unsigned char*	framepixels;
	psych_bool      isOES;

	// Called as 2nd personality "AddFrameToMovie" ?
	psych_bool isAddMovieFrame = PsychMatch(PsychGetFunctionName(), "AddFrameToMovie");

	// All sub functions should have these two lines
	if (isAddMovieFrame) {
		PsychPushHelp(useString2, synopsisString2, seeAlsoString);
	}
	else {
		PsychPushHelp(useString, synopsisString, seeAlsoString);
	}
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//cap the numbers of inputs and outputs
	PsychErrorExit(PsychCapNumInputArgs(5));   //The maximum number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(1));  //The maximum number of outputs
	
	// Get windowRecord for this window:
	PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);

    // Embedded subset has very limited support for readback formats :
    isOES = PsychIsGLES(windowRecord);

	// Make sure we don't execute on an onscreen window with pending async flip, as this would interfere
	// by touching the system backbuffer -> Impaired timing of the flip thread and undefined readback
	// of image data due to racing with the ops of the flipperthread on the same drawable.
	//
	// Note: It would be possible to allow drawBuffer readback if the drawBuffer is not multi-sampled
	// or if we can safely multisample-resolve without touching the backbuffer, but checking for all
	// special cases adds ugly complexity and is not really worth the effort, so we don't allow this.
	//
	// If this passes then PsychSetDrawingTarget() below will trigger additional validations to check
	// if execution of 'GetImage' is allowed under the current conditions for offscreen windows and
	// textures:
	if (PsychIsOnscreenWindow(windowRecord) && (windowRecord->flipInfo->asyncstate > 0)) {
		PsychErrorExitMsg(PsychError_user, "Calling this function on an onscreen window with a pending asynchronous flip is not allowed!");
	}

	// Set window as drawingtarget: Even important if this binding is changed later on!
	// We need to make sure all needed transitions are done - esp. in non-imaging mode,
	// so backbuffer is in a useable state:
	PsychSetDrawingTarget(windowRecord);
	
	// Disable shaders:
	PsychSetShader(windowRecord, 0);

	// Soft-Reset drawingtarget. This is important to make sure no FBO's are bound,
	// otherwise the following glGets for GL_DOUBLEBUFFER and GL_STEREO will retrieve
	// wrong results, leading to totally wrong read buffer assignments down the road!!
	PsychSetDrawingTarget((PsychWindowRecordType*) 0x1);

    // Queries only available on desktop OpenGL:
    if (!isOES) {
        glGetBooleanv(GL_DOUBLEBUFFER, &isDoubleBuffer);
        glGetBooleanv(GL_STEREO, &isStereo);
    }
    else {
        // Make something reasonable up:
        isStereo = FALSE;
        isDoubleBuffer = TRUE;
    }

    // Force "quad-buffered" stereo mode if our own homegrown implementation is active:
    if (windowRecord->stereomode == kPsychFrameSequentialStereo) isStereo = TRUE;
    
	// Assign read buffer:
	if(PsychIsOnscreenWindow(windowRecord)) {
		// Onscreen window: We read from the front- or front-left buffer by default.
		// This works on single-buffered and double buffered contexts in a consistent fashion:
		
		// Copy in optional override buffer name:
		PsychAllocInCharArg(3, FALSE, &buffername);
		
		// Override buffer name provided?
		if (buffername) {
			// Which one is it?
			
			// "frontBuffer" is always a valid choice:
			if (PsychMatch(buffername, "frontBuffer")) whichBuffer = GL_FRONT;
			// Allow selection of left- or right front stereo buffer in stereo mode:
			if (PsychMatch(buffername, "frontLeftBuffer") && isStereo) whichBuffer = GL_FRONT_LEFT;
			if (PsychMatch(buffername, "frontRightBuffer") && isStereo) whichBuffer = GL_FRONT_RIGHT;
			// Allow selection of backbuffer in double-buffered mode:
			if (PsychMatch(buffername, "backBuffer") && isDoubleBuffer) whichBuffer = GL_BACK;
			// Allow selection of left- or right back stereo buffer in stereo mode:
			if (PsychMatch(buffername, "backLeftBuffer") && isStereo && isDoubleBuffer) whichBuffer = GL_BACK_LEFT;
			if (PsychMatch(buffername, "backRightBuffer") && isStereo && isDoubleBuffer) whichBuffer = GL_BACK_RIGHT;
			// Allow AUX buffer access for debug purposes:
			if (PsychMatch(buffername, "aux0Buffer")) whichBuffer = GL_AUX0;
			if (PsychMatch(buffername, "aux1Buffer")) whichBuffer = GL_AUX1;
			if (PsychMatch(buffername, "aux2Buffer")) whichBuffer = GL_AUX2;
			if (PsychMatch(buffername, "aux3Buffer")) whichBuffer = GL_AUX3;

            // If 'drawBuffer' is requested, but imaging pipeline inactive, ie., there is no real 'drawBuffer', then we
            // map this to the backbuffer, as on a non-imaging configuration, the backbuffer is pretty much exactly the
            // equivalent of the 'drawBuffer':
            if (PsychMatch(buffername, "drawBuffer") && !(windowRecord->imagingMode & kPsychNeedFastBackingStore)) whichBuffer = GL_BACK;
		}
		else {
			// Default is frontbuffer:
			whichBuffer = GL_FRONT;
		}
	}
	else {
		// Offscreen window or texture: They only have one buffer, which is the
		// backbuffer in double-buffered mode and the frontbuffer in single buffered mode:
		whichBuffer=(isDoubleBuffer) ? GL_BACK : GL_FRONT;
	}
	
	// Enable this windowRecords framebuffer as current drawingtarget. This should
	// also allow us to "GetImage" from Offscreen windows:
	if ((windowRecord->imagingMode & kPsychNeedFastBackingStore) || (windowRecord->imagingMode & kPsychNeedFastOffscreenWindows)) {
		// Special case: Imaging pipeline active - We need to activate system framebuffer
		// so we really read the content of the framebuffer and not of some FBO:
		if (PsychIsOnscreenWindow(windowRecord)) {
			// It's an onscreen window:
            
            // Homegrown frame-sequential stereo active? Need to remap some stuff:
            if (windowRecord->stereomode == kPsychFrameSequentialStereo) {
                // Back/Front buffers map to backleft/frontleft buffers:
                if (whichBuffer == GL_BACK) whichBuffer = GL_BACK_LEFT;
                if (whichBuffer == GL_FRONT) whichBuffer = GL_FRONT_LEFT;
                
                // Special case: Want to read from stereo front buffer?
                if ((whichBuffer == GL_FRONT_LEFT) || (whichBuffer == GL_FRONT_RIGHT)) {
                    // These don't really exist in our homegrown implementation. Their equivalents are the
                    // regular system front/backbuffers. Due to the bufferswaps happening every video
                    // refresh cycle and the complex logic on when and how to blit finalizedFBOs into
                    // the system buffers and the asynchronous execution of the parallel flipper thread,
                    // we don't know which buffer (GL_BACK or GL_FRONT) corresponds to the leftFront or
                    // rightFront buffer. Let's be stupid and just return the current front buffer for
                    // FRONT_LEFT and the current back buffer for FRONT_RIGHT, but warn user about the
                    // ambiguity:
                    whichBuffer = (whichBuffer == GL_FRONT_LEFT) ? GL_FRONT : GL_BACK;
                    
                    if (PsychPrefStateGet_Verbosity() > 2) {
                        printf("PTB-WARNING: In Screen('GetImage'): You selected retrieval of one of the stereo front buffers, while our homegrown frame-sequential\n");
                        printf("PTB-WARNING: In Screen('GetImage'): stereo display mode is active. This will impair presentation timing and may cause flicker. The\n");
                        printf("PTB-WARNING: In Screen('GetImage'): mapping of 'frontLeftBuffer' and 'frontRightBuffer' to actual stimulus content is very ambiguous\n");
                        printf("PTB-WARNING: In Screen('GetImage'): in this mode. You may therefore end up with the content of the wrong buffer returned! Check results\n");
                        printf("PTB-WARNING: In Screen('GetImage'): carefully! Better read from 'backLeftBuffer' or 'backRightBuffer' for well defined results.\n\n");
                    }
                }
            }
            
            // Homegrown frame-sequential stereo active and backleft or backright buffer requested?
            if (((whichBuffer == GL_BACK_LEFT) || (whichBuffer == GL_BACK_RIGHT)) && (windowRecord->stereomode == kPsychFrameSequentialStereo)) {
                // We can get the equivalent of the backLeft/RightBuffer from the finalizedFBO's in this mode. Get their content:                
				viewid = (whichBuffer == GL_BACK_RIGHT) ? 1 : 0;
				whichBuffer = GL_COLOR_ATTACHMENT0_EXT;
                
                // Bind finalizedFBO as framebuffer to read from:
                glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, windowRecord->fboTable[windowRecord->finalizedFBO[viewid]]->fboid);
                
                // Make sure binding gets released at end of routine:
                viewid = -1;
                
            } // No frame-sequential stereo: Full imaging pipeline active and one of the drawBuffer's requested?
            else if (buffername && (PsychMatch(buffername, "drawBuffer")) && (windowRecord->imagingMode & kPsychNeedFastBackingStore)) {
				// Activate drawBufferFBO:
				PsychSetDrawingTarget(windowRecord);
				whichBuffer = GL_COLOR_ATTACHMENT0_EXT;
				
				// Is the drawBufferFBO multisampled?
				viewid = (((windowRecord->stereomode > 0) && (windowRecord->stereodrawbuffer == 1)) ? 1 : 0);
				if (windowRecord->fboTable[windowRecord->drawBufferFBO[viewid]]->multisample > 0) {
					// It is! We can't read from a multisampled FBO. Need to perform a multisample resolve operation and read
					// from the resolved unisample buffer instead. This is only safe if the unisample buffer is either a dedicated
					// FBO, or - in case its the final system backbuffer etc. - if preflip operations haven't been performed yet.
					// If non dedicated buffer (aka finalizedFBO) and preflip ops have already happened, then the backbuffer contains
					// final content for an upcoming Screen('Flip') and we can't use (and therefore taint) that buffer.
					if ((windowRecord->inputBufferFBO[viewid] == windowRecord->finalizedFBO[viewid]) && (windowRecord->backBufferBackupDone)) {
						// Target for resolve is finalized FBO (probably system backbuffer) and preflip ops have run already. We
						// can't do the resolve op, as this would screw up the backbuffer with the final stimulus:
						printf("PTB-ERROR: Tried to 'GetImage' from a multisampled 'drawBuffer', but can't perform anti-aliasing pass due to\n");
						printf("PTB-ERROR: lack of a dedicated resolve buffer.\n");
						printf("PTB-ERROR: You can get what you wanted by either one of two options:\n");
						printf("PTB-ERROR: Either enable a processing stage in the imaging pipeline, even if you don't need it, e.g., by setting\n");
						printf("PTB-ERROR: the imagingmode argument in the 'OpenWindow' call to kPsychNeedImageProcessing. This will create a\n");
						printf("PTB-ERROR: suitable resolve buffer. Or place the 'GetImage' call before any Screen('DrawingFinished') call, then\n");
						printf("PTB-ERROR: i can (ab-)use the system backbuffer as a temporary resolve buffer.\n\n");
						PsychErrorExitMsg(PsychError_user, "Tried to 'GetImage' from a multi-sampled 'drawBuffer'. Unsupported operation under given conditions.");						
					}
					else {
						// Ok, the inputBufferFBO is a suitable temporary resolve buffer. Perform a multisample resolve blit to it:
						// A simple glBlitFramebufferEXT() call will do the copy & downsample operation:
						glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, windowRecord->fboTable[windowRecord->drawBufferFBO[viewid]]->fboid);
						glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, windowRecord->fboTable[windowRecord->inputBufferFBO[viewid]]->fboid);
						glBlitFramebufferEXT(0, 0, windowRecord->fboTable[windowRecord->inputBufferFBO[viewid]]->width, windowRecord->fboTable[windowRecord->inputBufferFBO[viewid]]->height,
											 0, 0, windowRecord->fboTable[windowRecord->inputBufferFBO[viewid]]->width, windowRecord->fboTable[windowRecord->inputBufferFBO[viewid]]->height,
											 GL_COLOR_BUFFER_BIT, GL_NEAREST);

						// Bind inputBuffer as framebuffer:
						glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, windowRecord->fboTable[windowRecord->inputBufferFBO[viewid]]->fboid);
						viewid = -1;
					}
				}
			}
			else {
				// No: Activate system framebuffer:
				PsychSetDrawingTarget(NULL);
			}
		}
		else {
			// Offscreen window or texture: Select drawing target as usual,
			// but set color attachment as read buffer:
			PsychSetDrawingTarget(windowRecord);
			whichBuffer = GL_COLOR_ATTACHMENT0_EXT;

			// We do not support multisampled readout:
			if (windowRecord->fboTable[windowRecord->drawBufferFBO[0]]->multisample > 0) {
				printf("PTB-ERROR: You tried to Screen('GetImage', ...); from an offscreen window or texture which has multisample anti-aliasing enabled.\n");
				printf("PTB-ERROR: This operation is not supported. You must first use Screen('CopyWindow') to create a non-multisampled copy of the\n");
				printf("PTB-ERROR: texture or offscreen window, then use 'GetImage' on that copy. The copy will be anti-aliased, so you'll get what you\n");
				printf("PTB-ERROR: wanted with a bit more effort. Sorry for the inconvenience, but this is mostly a hardware limitation.\n\n");
				
				PsychErrorExitMsg(PsychError_user, "Tried to 'GetImage' from a multi-sampled texture or offscreen window. Unsupported operation.");
			}
		}
	}
	else {
		// Normal case: No FBO based imaging - Select drawing target as usual:
		PsychSetDrawingTarget(windowRecord);
	}
	
    if (!isOES) {
        // Select requested read buffer, after some double-check:
        if (whichBuffer == 0) PsychErrorExitMsg(PsychError_user, "Invalid or unknown 'bufferName' argument provided.");
        glReadBuffer(whichBuffer);

        if (PsychPrefStateGet_Verbosity() > 5) printf("PTB-DEBUG: In Screen('GetImage'): GL-Readbuffer whichBuffer = %i\n", whichBuffer);
    }
    else {
        // OES: No way to select readbuffer, it is "hard-coded" by system spec, depending
        // on framebuffer. For bound FBO, always color attachment zero, for system framebuffer,
        // always front buffer on single-buffered setup, back buffer on double-buffered setup:
        if (buffername && PsychIsOnscreenWindow(windowRecord) && (whichBuffer != GL_COLOR_ATTACHMENT0_EXT)) {
            // Some part of the real system framebuffer of an onscreen window explicitely requested.
            if ((windowRecord->windowType == kPsychSingleBufferOnscreen) && (whichBuffer != GL_FRONT) && (PsychPrefStateGet_Verbosity() > 1)) {
                printf("PTB-WARNING: Tried to Screen('GetImage') single-buffered framebuffer '%s', but only 'frontBuffer' supported on OpenGL-ES. Returning that instead.\n", buffername);
            }
            
            if ((windowRecord->windowType == kPsychDoubleBufferOnscreen) && (whichBuffer != GL_BACK) && (PsychPrefStateGet_Verbosity() > 1)) {
                printf("PTB-WARNING: Tried to Screen('GetImage') double-buffered framebuffer '%s', but only 'backBuffer' supported on OpenGL-ES. Returning that instead.\n", buffername);
            }
        }
    }

    if (whichBuffer == GL_COLOR_ATTACHMENT0_EXT) {
        // FBO of texture / offscreen window / onscreen drawBuffer/inputBuffer
        // has size of clientrect -- potentially larger or smaller than backbuffer:
        PsychCopyRect(windowRect, windowRecord->clientrect);
    }
    else {
        // Non-FBO backed texture / offscreen window / onscreen window has size
        // of raw rect (==clientrect for non-onscreen, == backbuffer size for onscreen):
        PsychCopyRect(windowRect, windowRecord->rect);
    }

	// Retrieve optional read rectangle:    
	if(!PsychCopyInRectArg(2, FALSE, sampleRect)) PsychCopyRect(sampleRect, windowRect);
    
	if (IsPsychRectEmpty(sampleRect)) return(PsychError_none);

	// Compute sampling rectangle:
	if ((PsychGetWidthFromRect(sampleRect) >= INT_MAX) || (PsychGetHeightFromRect(sampleRect) >= INT_MAX)) {
		PsychErrorExitMsg(PsychError_user, "Too big 'rect' argument provided. Both width and height of the rect must not exceed 2^31 pixels!");
	}

	sampleRectWidth = (size_t) PsychGetWidthFromRect(sampleRect);
	sampleRectHeight= (size_t) PsychGetHeightFromRect(sampleRect);

	// Regular image fetch to runtime, or adding to a movie?
	if (!isAddMovieFrame) {
		// Regular fetch:

		// Get optional floatprecision flag: We return data with float-precision if
		// this flag is set. By default we return uint8 data:
		PsychCopyInFlagArg(4, FALSE, &floatprecision);
		
		// Get the optional number of channels flag: By default we return 3 channels,
		// the Red, Green, and blue color channel:
		nrchannels = 3;
		PsychCopyInIntegerArg(5, FALSE, &nrchannels);
		if (nrchannels < 1 || nrchannels > 4) PsychErrorExitMsg(PsychError_user, "Number of requested channels 'nrchannels' must be between 1 and 4!");
		
		if (!floatprecision) {
			// Readback of standard 8bpc uint8 pixels:  

            // No Luminance + Alpha on OES:
            if (isOES && (nrchannels == 2)) PsychErrorExitMsg(PsychError_user, "Number of requested channels 'nrchannels' == 2 not supported on OpenGL-ES!");

			PsychAllocOutUnsignedByteMatArg(1, TRUE, (int) sampleRectHeight, (int) sampleRectWidth, (int) nrchannels, &returnArrayBase);
            if (isOES) {
                // We only do RGBA reads on OES, then discard unwanted stuff ourselves:
                redPlane  = (psych_uint8*) PsychMallocTemp((size_t) 4 * sampleRectWidth * sampleRectHeight);
            }
            else {
                redPlane  = (psych_uint8*) PsychMallocTemp((size_t) nrchannels * sampleRectWidth * sampleRectHeight);
            }
			planeSize = sampleRectWidth * sampleRectHeight;

			glPixelStorei(GL_PACK_ALIGNMENT,1);
			invertedY = (int) (windowRect[kPsychBottom] - sampleRect[kPsychBottom]);

            if (isOES) {
                glReadPixels((int) sampleRect[kPsychLeft], invertedY, (int) sampleRectWidth, (int) sampleRectHeight, GL_RGBA, GL_UNSIGNED_BYTE, redPlane);
                stride = 4;
            }
            else {
                stride = nrchannels;
                if (nrchannels==1) glReadPixels((int) sampleRect[kPsychLeft], invertedY, (int) sampleRectWidth, (int) sampleRectHeight, GL_RED, GL_UNSIGNED_BYTE, redPlane); 
                if (nrchannels==2) glReadPixels((int) sampleRect[kPsychLeft], invertedY, (int) sampleRectWidth, (int) sampleRectHeight, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, redPlane);
                if (nrchannels==3) glReadPixels((int) sampleRect[kPsychLeft], invertedY, (int) sampleRectWidth, (int) sampleRectHeight, GL_RGB, GL_UNSIGNED_BYTE, redPlane);
                if (nrchannels==4) glReadPixels((int) sampleRect[kPsychLeft], invertedY, (int) sampleRectWidth, (int) sampleRectHeight, GL_RGBA, GL_UNSIGNED_BYTE, redPlane);
            }
			
			//in one pass transpose and flip what we read with glReadPixels before returning.  
			//-glReadPixels insists on filling up memory in sequence by reading the screen row-wise whearas Matlab reads up memory into columns.
			//-the Psychtoolbox screen as setup by gluOrtho puts 0,0 at the top left of the window but glReadPixels always believes that it's at the bottom left.     
			for(ix=0; ix < sampleRectWidth; ix++){
				for(iy=0; iy < sampleRectHeight; iy++){
					// Compute write-indices for returned data:
					redReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth, nrchannels, iy, ix, 0);
					greenReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth,  nrchannels, iy, ix, 1);
					blueReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth,  nrchannels, iy, ix, 2);
					alphaReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth,  nrchannels, iy, ix, 3);
					
					// Always return RED/LUMINANCE channel:
					returnArrayBase[redReturnIndex] = redPlane[(ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth) * (size_t) stride + 0];  
					// Other channels on demand:
					if (nrchannels>1) returnArrayBase[greenReturnIndex] = redPlane[(ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth) * (size_t) stride + 1];
					if (nrchannels>2) returnArrayBase[blueReturnIndex]  = redPlane[(ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth) * (size_t) stride + 2];
					if (nrchannels>3) returnArrayBase[alphaReturnIndex] = redPlane[(ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth) * (size_t) stride + 3];
				}
			}		
		}
		else {
			// Readback of standard 32bpc float pixels into a double matrix:  

            // No Luminance + Alpha on OES:
            if (isOES && (nrchannels == 2)) PsychErrorExitMsg(PsychError_user, "Number of requested channels 'nrchannels' == 2 not supported on OpenGL-ES!");

            // Only float readback on floating point FBO's with EXT_color_buffer_float support:
            if (isOES && ((whichBuffer != GL_COLOR_ATTACHMENT0_EXT) || (windowRecord->bpc < 16) || !glewIsSupported("GL_EXT_color_buffer_float"))) {
                printf("PTB-ERROR: Tried to 'GetImage' pixels in floating point format from a non-floating point surface, or not supported by your hardware.\n");
                PsychErrorExitMsg(PsychError_user, "'GetImage' of floating point values from given object not supported on OpenGL-ES!");
            }

			PsychAllocOutDoubleMatArg(1, TRUE, (int) sampleRectHeight, (int) sampleRectWidth, (int) nrchannels, &returnArrayBaseDouble);
            if (isOES) {
                dredPlane = (float*) PsychMallocTemp((size_t) 4 * sizeof(float) * sampleRectWidth * sampleRectHeight);
                stride = 4;
            }
            else {
                dredPlane = (float*) PsychMallocTemp((size_t) nrchannels * sizeof(float) * sampleRectWidth * sampleRectHeight);
                stride = nrchannels;
            }
			planeSize = sampleRectWidth * sampleRectHeight * sizeof(float);

			glPixelStorei(GL_PACK_ALIGNMENT, 1);
			invertedY = (int) (windowRect[kPsychBottom]-sampleRect[kPsychBottom]);

            if (!isOES) {
                if (nrchannels==1) glReadPixels((int) sampleRect[kPsychLeft], invertedY, (int) sampleRectWidth, (int) sampleRectHeight, GL_RED, GL_FLOAT, dredPlane); 
                if (nrchannels==2) glReadPixels((int) sampleRect[kPsychLeft], invertedY, (int) sampleRectWidth, (int) sampleRectHeight, GL_LUMINANCE_ALPHA, GL_FLOAT, dredPlane);
                if (nrchannels==3) glReadPixels((int) sampleRect[kPsychLeft], invertedY, (int) sampleRectWidth, (int) sampleRectHeight, GL_RGB, GL_FLOAT, dredPlane);
                if (nrchannels==4) glReadPixels((int) sampleRect[kPsychLeft], invertedY, (int) sampleRectWidth, (int) sampleRectHeight, GL_RGBA, GL_FLOAT, dredPlane);
            }
            else {
                glReadPixels((int) sampleRect[kPsychLeft], invertedY, (int) sampleRectWidth, (int) sampleRectHeight, GL_RGBA, GL_FLOAT, dredPlane);
            }

			//in one pass transpose and flip what we read with glReadPixels before returning.  
			//-glReadPixels insists on filling up memory in sequence by reading the screen row-wise whearas Matlab reads up memory into columns.
			//-the Psychtoolbox screen as setup by gluOrtho puts 0,0 at the top left of the window but glReadPixels always believes that it's at the bottom left.     
			for(ix=0; ix < sampleRectWidth; ix++){
				for(iy=0; iy < sampleRectHeight; iy++){
					// Compute write-indices for returned data:
					redReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth, nrchannels, iy, ix, 0);
					greenReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth,  nrchannels, iy, ix, 1);
					blueReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth,  nrchannels, iy, ix, 2);
					alphaReturnIndex=PsychIndexElementFrom3DArray(sampleRectHeight, sampleRectWidth,  nrchannels, iy, ix, 3);
					
					// Always return RED/LUMINANCE channel:
					returnArrayBaseDouble[redReturnIndex] = dredPlane[(ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth) * (size_t) stride + 0];  
					// Other channels on demand:
					if (nrchannels>1) returnArrayBaseDouble[greenReturnIndex] = dredPlane[(ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth) * (size_t) stride + 1];
					if (nrchannels>2) returnArrayBaseDouble[blueReturnIndex]  = dredPlane[(ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth) * (size_t) stride + 2];
					if (nrchannels>3) returnArrayBaseDouble[alphaReturnIndex] = dredPlane[(ix + ((sampleRectHeight-1) - iy ) * sampleRectWidth) * (size_t) stride + 3];
				}
			}		
		}
	}
	
	if (isAddMovieFrame) {
		// Adding of image to a movie requested:
		
		// Get optional moviehandle:
		moviehandle = 0;
		PsychCopyInIntegerArg(4, FALSE, &moviehandle);
		if (moviehandle < 0) PsychErrorExitMsg(PsychError_user, "Provided 'moviehandle' is negative. Must be greater or equal to zero!");
		
		// Get optional frameduration:
		frameduration = 1;
		PsychCopyInIntegerArg(5, FALSE, &frameduration);
		if (frameduration < 1) PsychErrorExitMsg(PsychError_user, "Number of requested framedurations 'frameduration' is negative. Must be greater than zero!");
		
        framepixels = PsychGetVideoFrameForMoviePtr(moviehandle, &twidth, &theight, &numChannels, &bitdepth);
		if (framepixels) {
			glPixelStorei(GL_PACK_ALIGNMENT,1);
			invertedY = (int) (windowRect[kPsychBottom] - sampleRect[kPsychBottom]);
			
            if (isOES) {
                if (bitdepth != 8) PsychErrorExitMsg(PsychError_user, "AddFrameToMovie failed due to wrong bpc value. Only 8 bpc supported on OpenGL-ES.");

                if (numChannels == 4) {
                    // OES: BGRA supported?
                    if (glewIsSupported("GL_EXT_read_format_bgra")) {
                        // Yep: Readback in a compatible and acceptably fast format:
                        glReadPixels((int) sampleRect[kPsychLeft], invertedY, twidth, theight, GL_BGRA, GL_UNSIGNED_BYTE, framepixels);
                    }
                    else {
                        // Suboptimal readback path. will also cause swapped colors in movie writing:
                        glReadPixels((int) sampleRect[kPsychLeft], invertedY, twidth, theight, GL_RGBA, GL_UNSIGNED_BYTE, framepixels);
                    }
                }
                else if (numChannels == 3) {
                    glReadPixels((int) sampleRect[kPsychLeft], invertedY, twidth, theight, GL_RGB, GL_UNSIGNED_BYTE, framepixels);
                }
                else PsychErrorExitMsg(PsychError_user, "AddFrameToMovie failed due to wrong number of channels. Only 3 or 4 channels are supported on OpenGL-ES.");
            }
            else {
                // Desktop-GL: Use optimal format and support 16 bpc bitdepth as well.
                switch (numChannels) {
                    case 4:
                        glReadPixels((int) sampleRect[kPsychLeft], invertedY, twidth, theight, GL_BGRA, (bitdepth <= 8) ? GL_UNSIGNED_INT_8_8_8_8 : GL_UNSIGNED_SHORT, framepixels);
                        break;
                        
                    case 3:
                        glReadPixels((int) sampleRect[kPsychLeft], invertedY, twidth, theight, GL_RGB, (bitdepth <= 8) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT, framepixels);
                        break;
                        
                    case 1:
                        glReadPixels((int) sampleRect[kPsychLeft], invertedY, twidth, theight, GL_RED, (bitdepth <= 8) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT, framepixels);
                        break;
                        
                    default:
                        PsychErrorExitMsg(PsychError_user, "AddFrameToMovie failed due to wrong number of channels. Only 1, 3 or 4 channels are supported on OpenGL.");
                        break;
                }
            }

            // Add frame to movie, mark it as "upside down", with invalid -1 timestamp and a duration of frameduration ticks:
			if (PsychAddVideoFrameToMovie(moviehandle, frameduration, TRUE, -1) != 0) {
				PsychErrorExitMsg(PsychError_user, "AddFrameToMovie failed with error above!");
			}
		}
		else {
			PsychErrorExitMsg(PsychError_user, "Invalid 'moviePtr' provided. Doesn't correspond to a movie open for recording!");
		}
	}
	
	if (viewid == -1) {
		// Need to reset framebuffer binding to get rid of the inputBufferFBO which is bound due to
		// multisample resolve ops, or of other special FBO bindings --> Activate system framebuffer:
		PsychSetDrawingTarget(NULL);		
	}

	return(PsychError_none);
}
PsychError EyelinkMessage(void)
{
   int i, numInArgs;
   int status = -1;
   void **args_ptr = NULL; /* argument list, used as a va_list */
   char s[256];
   char *formatString;
   PsychArgFormatType format;
   double tempValue;
   char *tempString = NULL;
   
   //all sub functions should have these two lines
   PsychPushHelp(useString, synopsisString, seeAlsoString);
   if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

   //check to see if the user supplied superfluous arguments
   // PsychErrorExit(PsychCapNumInputArgs(1));
   PsychErrorExit(PsychRequireNumInputArgs(1));
   PsychErrorExit(PsychCapNumOutputArgs(1));
   
   	// Verify eyelink is up and running
	EyelinkSystemIsConnected();
	EyelinkSystemIsInitialized();
   
   PsychAllocInCharArg(1, TRUE, &formatString);
   numInArgs = PsychGetNumInputArgs();   

   if (numInArgs > 1)
   {
      args_ptr = (void **)mxMalloc((numInArgs-1) * sizeof(char *));
      //iterate over each of the supplied inputs.  
      for(i=2;i<=numInArgs;i++){
         format = PsychGetArgType(i);
         switch(format){
            case PsychArgType_double:
               if(PsychGetArgM(i)==1 && PsychGetArgN(i)==1){
                  PsychCopyInDoubleArg(i, TRUE, &tempValue);
                  args_ptr[i-2] = (void *) (int) tempValue;
               }
               else
               {
                  PsychGiveHelp();
                  return(PsychError_user);
               }
               break;
            case PsychArgType_char:
               args_ptr[i-2] = NULL;
               PsychAllocInCharArg(i, TRUE, &tempString); 
               args_ptr[i-2] = tempString;
               break;
            default:
               PsychGiveHelp();
               return(PsychError_user);
               break;
         }
      }
   }

   vsprintf(s, formatString, (va_list)args_ptr);

   status = eyemsg_printf(s);

   if (args_ptr != NULL)
      mxFree(args_ptr);

   /* if there is an output variable available, assign eyecmd_printf status to it.   */
   PsychCopyOutDoubleArg(1, FALSE, status);
   
   return(PsychError_none);
}
PsychError SCREENTextBounds(void) 
{
	//for debugging
	TextEncodingBase		textEncodingBase;
	TextEncodingVariant		textEncodingVariant;
	TextEncodingFormat		textEncodingFormat;
	
	///////
        PsychWindowRecordType           *winRec;
	char				*textCString;
	Str255				textPString;
	UniChar				*textUniString;
	OSStatus			callError;
	PsychRectType			resultPsychRect, resultPsychNormRect;
	ATSUTextLayout			textLayout;				//layout is a pointer to an opaque struct.
	int				stringLengthChars;
	int				uniCharBufferLengthElements, uniCharBufferLengthChars, uniCharBufferLengthBytes;
	ByteCount			uniCharStringLengthBytes;
	TextToUnicodeInfo		textToUnicodeInfo;
	TextEncoding			textEncoding;
	ATSUStyle			atsuStyle;
	Boolean				foundFont;
	
	//for ATSU  style attributes
	PsychFontStructPtrType  psychFontRecord;

    			
        //all subfunctions should have these two lines.  
        PsychPushHelp(useString, synopsisString, seeAlsoString);
        if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
        //check for correct the number of arguments before getting involved
        PsychErrorExit(PsychCapNumInputArgs(2));   	
        PsychErrorExit(PsychRequireNumInputArgs(2)); 	
        PsychErrorExit(PsychCapNumOutputArgs(2));
	
	//get the window pointer and the text string and check that the window record has a font set
        PsychAllocInWindowRecordArg(1, kPsychArgRequired, &winRec);
	foundFont=PsychGetFontRecordFromFontNumber(winRec->textAttributes.textFontNumber, &psychFontRecord);
	if(!foundFont)
		PsychErrorExitMsg(PsychError_user, "Attempt to determine the bounds of text with no font or invalid font number");
		//it would be better to both prevent the user from setting invalid font numbers and init to the OS 9  default font.
	
	//read in the string and get its length and convert it to a unicode string.
	PsychAllocInCharArg(2, kPsychArgRequired, &textCString);
	stringLengthChars=strlen(textCString);
	if(stringLengthChars > 255)
		PsychErrorExitMsg(PsychError_unimplemented, "Cut corners and TextBounds will not accept a string longer than 255 characters");
	CopyCStringToPascal(textCString, textPString);
	uniCharBufferLengthChars= stringLengthChars * CHAR_TO_UNICODE_LENGTH_FACTOR;
	uniCharBufferLengthElements= uniCharBufferLengthChars + 1;		
	uniCharBufferLengthBytes= sizeof(UniChar) * uniCharBufferLengthElements;
	textUniString=(UniChar*)malloc(uniCharBufferLengthBytes);
	//Using a TextEncoding type describe the encoding of the text to be converteed.  
	textEncoding=CreateTextEncoding(kTextEncodingMacRoman, kMacRomanDefaultVariant, kTextEncodingDefaultFormat);
	//Take apart the encoding we just made to check it:
        textEncodingBase=GetTextEncodingBase(textEncoding);
        textEncodingVariant=GetTextEncodingVariant(textEncoding);
        textEncodingFormat=GetTextEncodingFormat(textEncoding);
	//Create a structure holding conversion information from the text encoding type we just created.
	callError=CreateTextToUnicodeInfoByEncoding(textEncoding,&textToUnicodeInfo);
	//Convert the text to a unicode string
	callError=ConvertFromPStringToUnicode(textToUnicodeInfo, textPString, (ByteCount)uniCharBufferLengthBytes,	&uniCharStringLengthBytes,	textUniString);
	//create the text layout object
	callError=ATSUCreateTextLayout(&textLayout);			
	//associate our unicode text string with the text layout object
	callError=ATSUSetTextPointerLocation(textLayout, textUniString, kATSUFromTextBeginning, kATSUToTextEnd, (UniCharCount)stringLengthChars);
	
	//create an ATSU style object
	callError=ATSUCreateStyle(&atsuStyle);
	callError=ATSUClearStyle(atsuStyle);
	
	//Not that we have a style object we have to set style charactersitics.  These include but are more general than Font Manager styles.  
	//ATSU Style objects have three sets of characteristics:  attributes, variations, and features.
	//attributes are things we need to set to match OS 9 behavior, such as the font ID, size, boldness, and italicization.
	//features are esoteric settings which we don't need for reproducing OS 9 behavior.  Whatever clearstyle sets should be fine.
	//font variations are axes of variation through the space of font characteristics.  The font definition includes available axes of variation.  Something else we can ignore for now.  
	PsychSetATSUStyleAttributesFromPsychWindowRecord(atsuStyle, winRec);
	//don't bother to set the variations of the style.
	//don't bother to set the features of the style.
	
	//associate the style with our layout object. This call assigns a style to every character of the string to be displayed.  
	callError=ATSUSetRunStyle(textLayout, atsuStyle, (UniCharArrayOffset)0, (UniCharCount)stringLengthChars);

        //Get the bounds for our text so that and create a texture of sufficient size to containt it. 
        ATSTrapezoid trapezoid;
        ItemCount oActualNumberOfBounds = 0;
        callError=ATSUGetGlyphBounds(textLayout, 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 0, NULL, &oActualNumberOfBounds);
        if (callError || oActualNumberOfBounds!=1) {
            PsychErrorExitMsg(PsychError_internal, "Failed to compute bounding box in call 1 to ATSUGetGlyphBounds() (nrbounds!=1)\n");    
        }
        callError=ATSUGetGlyphBounds(textLayout, 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 1, &trapezoid, &oActualNumberOfBounds);
        if (callError || oActualNumberOfBounds!=1) {
            PsychErrorExitMsg(PsychError_internal, "Failed to retrieve bounding box in call 2 to ATSUGetGlyphBounds() (nrbounds!=1)\n");    
        }
        
        resultPsychRect[kPsychLeft]=(Fix2X(trapezoid.upperLeft.x) < Fix2X(trapezoid.lowerLeft.x)) ? Fix2X(trapezoid.upperLeft.x) : Fix2X(trapezoid.lowerLeft.x);
        resultPsychRect[kPsychRight]=(Fix2X(trapezoid.upperRight.x) > Fix2X(trapezoid.lowerRight.x)) ? Fix2X(trapezoid.upperRight.x) : Fix2X(trapezoid.lowerRight.x);
        resultPsychRect[kPsychTop]=(Fix2X(trapezoid.upperLeft.y) < Fix2X(trapezoid.upperRight.y)) ? Fix2X(trapezoid.upperLeft.y) : Fix2X(trapezoid.upperRight.y);
        resultPsychRect[kPsychBottom]=(Fix2X(trapezoid.lowerLeft.y) > Fix2X(trapezoid.lowerRight.y)) ? Fix2X(trapezoid.lowerLeft.y) : Fix2X(trapezoid.lowerRight.y);

	PsychNormalizeRect(resultPsychRect, resultPsychNormRect);

	PsychCopyOutRectArg(1, FALSE, resultPsychNormRect);
	PsychCopyOutRectArg(2, FALSE, resultPsychRect);


	//release resources
	free((void*)textUniString);
	callError=ATSUDisposeStyle(atsuStyle);

    return(PsychError_none);
}
PsychError SCREENOpenVideoCapture(void) 
{
	PsychWindowRecordType			*windowRecord;
	int                                     deviceIndex;
	int                                     capturehandle = -1;
	double                                  framerate;
	int                                     width;
	int                                     height;
	PsychRectType                           roirectangle;
	psych_bool                              roiassigned;
	int                                     reqdepth = 0;
	int                                     num_dmabuffers = 0;
	int                                     allow_lowperf_fallback = 1;
	char*					moviename;
	int					recordingflags;
	int					engineId;
	
	// All sub functions should have these two lines
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none);};

	PsychErrorExit(PsychCapNumInputArgs(9));            // Max. 9 input args.
	PsychErrorExit(PsychRequireNumInputArgs(1));        // Min. 1 input args required.
	PsychErrorExit(PsychCapNumOutputArgs(1));           // Max. 1 output args.
	
	// Get the window record from the window record argument and get info from the window record
	PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
	// Only onscreen windows allowed:
	if(!PsychIsOnscreenWindow(windowRecord)) {
		PsychErrorExitMsg(PsychError_user, "OpenVideoCapture called on something else than an onscreen window.");
	}
	
	// Get the device index. We default to the first device if none is given:
	deviceIndex=0;
	PsychCopyInIntegerArg(2, FALSE, &deviceIndex);
	
	// Get the optional roi rectangle:
	roiassigned = PsychCopyInRectArg(3, FALSE, roirectangle);
	if (roiassigned && IsPsychRectEmpty(roirectangle)) PsychErrorExitMsg(PsychError_user, "OpenVideoCapture called with invalid (empty) roirectangle argument.");
	
	// Query (optional) output texture pixel depth: By default, we take whatever we get from the capture device:
	PsychCopyInIntegerArg(4, FALSE, &reqdepth);
	if (reqdepth<0) PsychErrorExitMsg(PsychError_user, "OpenVideoCapture called with invalid (negative) pixeldepth argument.");
	// Query number of ringbuffers to use. Our default is coded in the OS dependent subroutines.
	PsychCopyInIntegerArg(5, FALSE, &num_dmabuffers);
	if (num_dmabuffers<0) PsychErrorExitMsg(PsychError_user, "OpenVideoCapture called with invalid (negative) numbuffers argument.");
	// Query, if use of low-performance fallback code is allowed if high-perf engine fails:
	PsychCopyInIntegerArg(6, FALSE, &allow_lowperf_fallback);
	if (allow_lowperf_fallback<0) PsychErrorExitMsg(PsychError_user, "OpenVideoCapture called with invalid (negative) allowfallback flag.");
	
	// Query optional moviename for recording the grabbed video into a Quicktime movie file:
	moviename = NULL;
	PsychAllocInCharArg(7, FALSE, &moviename);
	
	// Query optional movie recording flags:
	// 0 = Record video, stream to disk immediately (slower, but unlimited recording duration).
	// 1 = Record video, stream to memory, then at end of recording to disk (limited duration by RAM size, but faster).
	// 2 = Record audio as well.
	// 4 = Do not return capture data via Screen('GetCapturedImage') during video recording to disc.
	// 8 = Avoid some performance optimizations which may cause trouble with some codecs.
	// 16= Use multi-threading for automatic background processing and cpu offloading.
	// 32= Return high quality textures via 'GetCapturedImage' if recording in parallel --> Quality tradeoff live feed vs. recording.
	// 64= Return timestamps in engine time instead of GetSecs() time.
	recordingflags = 0;
	PsychCopyInIntegerArg(8, FALSE, &recordingflags);
	
	// Copy in optional id of video capture engine to use. We default to the one set via the Screen('Preference', 'DefaultVideocaptureEngine');
	// setting, which by itself defaults to LibDC1394 (type 1) on Linux, ARVideo (type 2) and Quicktime/SG (type 0) on OS/X for now.
	engineId = PsychPrefStateGet_VideoCaptureEngine();
	PsychCopyInIntegerArg(9, FALSE, &engineId);
	if (engineId < 0 || engineId > 3) PsychErrorExitMsg(PsychError_user, "OpenVideoCapture called with invalid 'captureEngineType'. Valid are 0,1,2,3.");

	if (engineId == 2) {
		printf("\n\n");
		printf("PTB-INFO: Your script explicitely requests use of video capture engine type 2 - the ARVideo video capture engine.\n");
		printf("PTB-INFO: This engine has been permanently disabled and removed from Psychtoolbox since beginning of the year 2011.\n");
		printf("PTB-INFO: We recommend use of the GStreamer video capture engine (engine type 3) as a technically superior replacement\n");
		printf("PTB-INFO: on GNU-Linux and MS-Windows. For Mac OS/X for now we recommend use of the Quicktime engine (engine type 0)\n");
		printf("PTB-INFO: as an interims solution. The Quicktime engine will be eventually replaced on OS/X by the GStreamer engine as well.\n");
		printf("PTB-INFO: In most cases, the selected replacement should work without need for any further changes to your code.\n\n");
	}

	// Try to open the capture device and create & initialize a corresponding capture object.
	// A MATLAB handle to the video capture object is returned upon successfull operation.
	if (roiassigned) {
		PsychOpenVideoCaptureDevice(engineId, windowRecord, deviceIndex, &capturehandle, roirectangle, reqdepth, num_dmabuffers, allow_lowperf_fallback, moviename, recordingflags);
	}
	else {
		PsychOpenVideoCaptureDevice(engineId, windowRecord, deviceIndex, &capturehandle, NULL, reqdepth, num_dmabuffers, allow_lowperf_fallback, moviename, recordingflags);
	}
	
	// Upon sucessfull completion, we'll have a valid handle in 'capturehandle'. Return it to Matlab-world:
	PsychCopyOutDoubleArg(1, TRUE, (double) capturehandle);
	
	// Ready!
	return(PsychError_none);
}
Beispiel #22
0
PsychError IOPORTWrite(void)
{
 	static char useString[] = "[nwritten, when, errmsg, prewritetime, postwritetime, lastchecktime] = IOPort('Write', handle, data [, blocking=1]);";
	static char synopsisString[] = 
		"Write data to device, specified by 'handle'.\n"
		"'data' must be a vector of data items to write, or a matrix (in which case data "
		"in the matrix will be transmitted in column-major order, ie., first the first "
		"column, then the 2nd column etc...), either with data elements of uint8 class "
		"or a (1 Byte per char) character string. The optional flag 'blocking' if "
		"set to 0 will ask the write function to not block, but return immediately, ie. "
		"data is sent/written in the background while your code continues to execute - There "
		"may be an arbitrary delay until data transmission is really finished. The default "
		"setting is 1, ie. blocking writes - The function waits until data transmission is really "
		"finished. You can also use blocking == 2 to request a different mode "
		"for blocking writes, where IOPort is polling for write-completion instead of "
		"a more cpu friendly wait. This may decrease latency for certain applications. "
		"Another even more agressive polling method is implemented via blocking == 3 on "
		"Linux systems with some limited set of hardware, e.g., real native serial ports.\n"
		"On systems without any support for specific polling modes, the 2 or 3 settings are treated "
		"as a standard blocking write.\n\n"
		"Optionally, the function returns the following return arguments:\n"
		"'nwritten' Number of bytes written -- Should match amount of data provided on success.\n"
		"'when' A timestamp of write completion: This is only meaningful in blocking mode!\n"
		"'errmsg' A system defined error message if something wen't wrong.\n"
		"The following three timestamps are for low-level debugging and special purpose:\n"
		"'prewritetime' A timestamp taken immediately before submitting the write request. "
		"'postwritetime' A timestamp taken immediately after submitting the write request. "
		"'lastchecktime' A timestamp taken at the time of last check for write completion if applicable. ";
		
	static char seeAlsoString[] = "";
	
	char			errmsg[1024];
	int				handle, blocking, m, n, p, nwritten;
	psych_uint8*	inData = NULL;
	char*			inChars = NULL;
	void*			writedata = NULL;
	double			timestamp[4] = {0, 0, 0, 0};
	errmsg[0] = 0;

	// Setup online help: 
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none); };
	
	PsychErrorExit(PsychCapNumInputArgs(3));     // The maximum number of inputs
	PsychErrorExit(PsychRequireNumInputArgs(2)); // The required number of inputs	
	PsychErrorExit(PsychCapNumOutputArgs(6));	 // The maximum number of outputs

	// Get required port handle:
	PsychCopyInIntegerArg(1, kPsychArgRequired, &handle);

	// Get the data:
	switch(PsychGetArgType(2)) {
		case PsychArgType_uint8:
			PsychAllocInUnsignedByteMatArg(2, kPsychArgRequired, &m, &n, &p, &inData);
			if (p!=1 || m * n == 0) PsychErrorExitMsg(PsychError_user, "'data' is not a vector or 2D matrix, but some higher dimensional matrix!");
			n = m * n;
			writedata = (void*) inData;
		break;
		
		case PsychArgType_char:
			PsychAllocInCharArg(2, kPsychArgRequired, &inChars);
			n = strlen(inChars);
			writedata = (void*) inChars;
		break;
		
		default:
			PsychErrorExitMsg(PsychError_user, "Invalid type for 'data' vector: Must be an uint8 or char vector.");
	}
	
	
	// Get optional blocking flag: Defaults to one -- blocking.
	blocking = 1;
	PsychCopyInIntegerArg(3, kPsychArgOptional, &blocking);

	// Write data:
	nwritten = PsychWriteIOPort(handle, writedata, n, blocking, errmsg, &timestamp[0]);
	if (nwritten < 0 && verbosity > 0) printf("IOPort: Error: %s\n", errmsg); 
	
	PsychCopyOutDoubleArg(1, kPsychArgOptional, nwritten);
	PsychCopyOutDoubleArg(2, kPsychArgOptional, timestamp[0]);
	PsychCopyOutCharArg(3, kPsychArgOptional, errmsg);
	PsychCopyOutDoubleArg(4, kPsychArgOptional, timestamp[1]);
	PsychCopyOutDoubleArg(5, kPsychArgOptional, timestamp[2]);
	PsychCopyOutDoubleArg(6, kPsychArgOptional, timestamp[3]);
	
    return(PsychError_none);
}
PsychError SCREENShowCursorHelper(void)
{
    // If you change the useString then also change the corresponding synopsis string in ScreenSynopsis.c
    static char useString[] = "Screen('ShowCursorHelper', screenIndex [, cursorshapeid][, mouseIndex]);";
    //                                                    1              2                3
    static char synopsisString[] =
    "This is a helper function called by ShowCursor.  Do not call Screen(\'ShowCursorHelper\'), use "
    "ShowCursor instead.\n"
    "Show the mouse pointer. If optional 'cursorshapeid' is given, select a specific cursor shape as well.\n"
    "If optional 'mouseIndex' is given, setup cursor for given master mouseIndex device (Linux only).\n";
    static char seeAlsoString[] = "HideCursorHelper";

    int	screenNumber, cursorid, mouseIdx;
    char *cursorName = NULL;

#if PSYCH_SYSTEM == PSYCH_LINUX
    Cursor  mycursor;
#endif

    //all subfunctions should have these two lines.
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    PsychErrorExit(PsychCapNumInputArgs(3));   //The maximum number of inputs
    PsychErrorExit(PsychCapNumOutputArgs(0));  //The maximum number of outputs

    PsychCopyInScreenNumberArg(1, TRUE, &screenNumber);

    mouseIdx = -1;
    PsychCopyInIntegerArg(3, FALSE, &mouseIdx);

    PsychShowCursor(screenNumber, mouseIdx);

    // Copy in optional cursor shape id argument: The default of -1 means to
    // not change cursor appearance. Any other positive value changes to an
    // OS dependent shape (== the mapping of numbers to shapes is OS dependent).
    cursorid = -1;
    if (!PsychCopyInIntegerArg(2, kPsychArgAnything, &cursorid)) {
        if (PsychAllocInCharArg(2, kPsychArgAnything, &cursorName)) cursorid = -2;
    }

    // Cursor change request?
    if (cursorid!=-1) {
        // Yes.
#if PSYCH_SYSTEM == PSYCH_OSX
        // OS/X:
        PsychCocoaSetThemeCursor(cursorid);
#endif

#if PSYCH_SYSTEM == PSYCH_LINUX

        #ifdef PTB_USE_WAYLAND
            // GNU/Linux with Wayland backend:

            // Map X11 id's to Wayland equivalents:
            switch (cursorid) {
                case 26: // SandClock
                    cursorName = "watch";
                break;

                case 58: // Hand
                    cursorName = "hand1";
                    break;

                case 34: // CrossHair
                    cursorName = "crosshair";
                    break;

                case 1: // IBeam
                    cursorName = "xterm";
                    break;

                case 0: // Arrow
                    cursorName = "left_ptr";
                    break;

                case 2: // Arrow
                    cursorName = "left_ptr";
                    break;

                case 5: // Arrow
                    cursorName = "left_ptr";
                    break;

                case -2: // Special case: Use provided cursorName string, if any:
                    if (cursorName) break;

                default:
                    cursorName = "left_ptr";
            }

            PsychOSDefineWaylandCursor(screenNumber, mouseIdx, cursorName);
        #else
            // GNU/Linux with X11 windowing system:
            // Map screenNumber to X11 display handle and screenid:
            CGDirectDisplayID dpy;
            PsychGetCGDisplayIDFromScreenNumber(&dpy, screenNumber);
            // Create cursor spec from passed cursorid:
            mycursor = XCreateFontCursor(dpy, (unsigned int) cursorid);
            if (mouseIdx < 0) {
                // Set cursor for our window:
                PsychOSDefineX11Cursor(screenNumber, -1, mycursor);
            } else {
                // XInput cursor: Master pointers only.
                int nDevices;
                XIDeviceInfo* indevs = PsychGetInputDevicesForScreen(screenNumber, &nDevices);

                // Sanity check:
                if (NULL == indevs) PsychErrorExitMsg(PsychError_user, "Sorry, your system does not support individual mouse pointers.");
                if (mouseIdx >= nDevices) PsychErrorExitMsg(PsychError_user, "Invalid 'mouseIndex' provided. No such cursor pointer.");
                if (indevs[mouseIdx].use != XIMasterPointer) PsychErrorExitMsg(PsychError_user, "Invalid 'mouseIndex' provided. No such master cursor pointer.");

                PsychOSDefineX11Cursor(screenNumber, indevs[mouseIdx].deviceid, mycursor);
            }

            XFlush(dpy);
        #endif
        // Done (hopefully).
#endif

#if PSYCH_SYSTEM == PSYCH_WINDOWS
        // Microsoft Windows:
        LPCTSTR lpCursorName;

        #ifndef IDC_HAND
        #define IDC_HAND MAKEINTRESOURCE(32649)
        #endif

        // Map provided cursor id to a Windows system id for such a cursor:
        switch(cursorid) {
            case 0:
                // Standard arrow cursor:
                lpCursorName = IDC_ARROW;
                break;

            case 1:
                // haircross cursor:
                lpCursorName = IDC_CROSS;
                break;

            case 2:
                // hand cursor:
                lpCursorName = IDC_HAND;
                break;

            case 3:
                // Arrows in all 4 directions cursor:
                lpCursorName = IDC_SIZEALL;
                break;

            case 4:
                // north-south cursor:
                lpCursorName = IDC_SIZENS;
                break;

            case 5:
                // east-west cursor:
                lpCursorName = IDC_SIZEWE;
                break;

            case 6:
                // hourglass cursor:
                lpCursorName = IDC_WAIT;
                break;

            case 7:
                // No cursor:
                lpCursorName = IDC_NO;
                break;

            case 8:
                // IBeam/text cursor:
                lpCursorName = IDC_IBEAM;
                break;

            default:
                // Default for unknown id is the standard arrow cursor:
                lpCursorName = IDC_ARROW;
        }

        // Load and set a cursor, based on the selected lpCursorName cursor id string:
        SetCursor(LoadCursor(NULL, lpCursorName));
#endif
        // End of cursor shape setup.
    }

    return(PsychError_none);
}
PsychError SCREENPreference(void)  
{

	PsychArgFormatType		arg1Type;
	char					*preferenceName, *newFontName;
	const char				*tableCreator, *oldDefaultFontName;
	Boolean					preferenceNameArgumentValid, booleanInput, ignoreCase, tempFlag, textAlphaBlendingFlag, suppressAllWarningsFlag;
	int						numInputArgs, i, newFontStyleNumber, newFontSize, tempInt;
	double					returnDoubleValue, inputDoubleValue;
	
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous or missing arguments
	PsychErrorExit(PsychCapNumInputArgs(3));			
	PsychErrorExit(PsychRequireNumInputArgs(1));		   
	PsychErrorExit(PsychCapNumOutputArgs(1));
	
	numInputArgs=PsychGetNumInputArgs();
	arg1Type=PsychGetArgType(1);
	preferenceNameArgumentValid=FALSE;
	
	//Cases which require both a window pointer or screen number and preference name.  Argument 1 is the wposn and argument 2 is the preference name.
	if( numInputArgs >= 2 && (PsychIsScreenNumberArg(1) || PsychIsScreenNumberArg(1)) && PsychGetArgType(2)==PsychArgType_char ){
		PsychAllocInCharArg(2, kPsychArgRequired, &preferenceName);
		//preferences which require window pointer or screen number argument which we DO NOT support  
		for(i=0;i<kPsychNumUnsupportedMacVideoPreferences;i++){
			if(PsychMatch(preferenceName, unsupportedMacVideoPreferenceNames[i]))
				PsychErrorExit(PsychError_unsupportedOS9Preference);
		}
		//insert here conditionals  to act on prefernces which accept a window pointer or screen number argument which we DO support.
		PsychErrorExit(PsychError_unrecognizedPreferenceName);
	}

	//Cases which do not require a wposn.  Argument 1 is the preference name.  if present Argument 2 is the new value
	if(arg1Type==PsychArgType_char){
		PsychAllocInCharArg(1, kPsychArgRequired, &preferenceName);
		//Preferernces which we do not support and which do not require a wposn
		for(i=0;i<kPsychNumUnsupportedMacNonVideoPreferences;i++){
			if(PsychMatch(preferenceName, unsupportedMacNonVideoPreferenceNames[i]))
				PsychErrorExit(PsychError_unsupportedOS9Preference);
		}
		//Preferences which we do support
		if(PsychMatch(preferenceName, "IgnoreCase")){
			ignoreCase=!PsychIsPsychMatchCaseSensitive();
			PsychCopyOutFlagArg(1, kPsychArgOptional, ignoreCase);
			if(numInputArgs==2){
				PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
				PsychSetPsychMatchCaseSenstive(!booleanInput);			
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "Tick0Secs")){
			if(PsychCopyInDoubleArg(2, kPsychArgOptional, &inputDoubleValue) && inputDoubleValue==PsychGetNanValue())
				PsychEstimateGetSecsValueAtTickCountZero();
			returnDoubleValue=PsychGetEstimatedSecsValueAtTickCountZero();
			PsychCopyOutDoubleArg(1, kPsychArgOptional, returnDoubleValue);
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "PsychTableVersion")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)PsychPrefStateGet_PsychTableVersion());
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "PsychTableCreator")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			tableCreator=PsychPrefStateGet_PsychTableCreator();
			PsychCopyOutCharArg(1, kPsychArgOptional, tableCreator);
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "Process")){
			if(numInputArgs==2)
				PsychErrorExit(PsychError_extraInputArg);
			PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)getpid());
			preferenceNameArgumentValid=TRUE;


		}else 
		if(PsychMatch(preferenceName, "DefaultFontName")){
			PsychPrefStateGet_DefaultFontName(&oldDefaultFontName);
			PsychCopyOutCharArg(1, kPsychArgOptional, oldDefaultFontName);
			if(numInputArgs==2){
				PsychAllocInCharArg(2, kPsychArgRequired, &newFontName);
				PsychPrefStateSet_DefaultFontName(newFontName);
			}
			preferenceNameArgumentValid=TRUE;
			
		}else 
		if(PsychMatch(preferenceName, "DefaultFontStyle")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DefaultTextStyle());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &newFontStyleNumber);
				PsychPrefStateSet_DefaultTextStyle(newFontStyleNumber);
			}
			preferenceNameArgumentValid=TRUE;
		}else
		if(PsychMatch(preferenceName, "DefaultTextYPositionIsBaseline")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_TextYPositionIsBaseline());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_TextYPositionIsBaseline(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "DefaultFontSize")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DefaultTextSize());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &newFontSize);
				PsychPrefStateSet_DefaultTextSize(newFontSize);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
		if(PsychMatch(preferenceName, "DebugMakeTexture")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_DebugMakeTexture());
			if(numInputArgs==2){
				PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
				PsychPrefStateSet_DebugMakeTexture(tempFlag);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SkipSyncTests")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_SkipSyncTests());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_SkipSyncTests(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VisualDebugLevel")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VisualDebugLevel());
			if(numInputArgs==2){
				PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
				PsychPrefStateSet_VisualDebugLevel(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "VBLTimestampingMode")){
			PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_VBLTimestampingMode());
			if(numInputArgs==2){
                            PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
                            PsychPrefStateSet_VBLTimestampingMode(tempInt);
			}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "ConserveVRAM")){
					PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_ConserveVRAM());
					if(numInputArgs==2){
						PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
						PsychPrefStateSet_ConserveVRAM(tempInt);
					}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "Verbosity")){
					PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_Verbosity());
					if(numInputArgs==2){
						PsychCopyInIntegerArg(2, kPsychArgRequired, &tempInt);
						PsychPrefStateSet_Verbosity(tempInt);
					}
			preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "EmulateOldPTB")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_EmulateOldPTB());
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
					PsychPrefStateSet_EmulateOldPTB(tempFlag);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "Enable3DGraphics")){
				PsychCopyOutDoubleArg(1, kPsychArgOptional, PsychPrefStateGet_3DGfx());
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &tempFlag);
					PsychPrefStateSet_3DGfx(tempFlag);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "TextAlphaBlending")){
				textAlphaBlendingFlag=PsychPrefStateGet_TextAlphaBlending();
				PsychCopyOutFlagArg(1, kPsychArgOptional, textAlphaBlendingFlag);
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
					PsychPrefStateSet_TextAlphaBlending(booleanInput);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			if(PsychMatch(preferenceName, "SuppressAllWarnings")){
				suppressAllWarningsFlag=PsychPrefStateGet_SuppressAllWarnings();
				PsychCopyOutFlagArg(1, kPsychArgOptional, suppressAllWarningsFlag);
				if(numInputArgs==2){
					PsychCopyInFlagArg(2, kPsychArgRequired, &booleanInput);
					PsychPrefStateSet_SuppressAllWarnings(booleanInput);
				}
				preferenceNameArgumentValid=TRUE;
		}else 
			PsychErrorExit(PsychError_unrecognizedPreferenceName);
	}
	
	if(!preferenceNameArgumentValid)
		PsychErrorExitMsg(PsychError_user, "Invalid arguments to preferences command");
		
	return(PsychError_none);
}
PsychError SCREENCreateMovie(void)
{
	static char useString[] = "moviePtr = Screen('CreateMovie', windowPtr, movieFile [, width][, height][, frameRate=30][, movieOptions]);";
	static char synopsisString[] = 
		"Create a new movie file with filename 'movieFile' and according to given 'movieOptions'.\n"
		"The function returns a handle 'moviePtr' to the file.\n"
		"Currently, movie creation and recording is only supported on OS/X and Windows, as it "
		"needs Apple's Quicktime to be installed. It can use any Quicktime codec that is installed "
		"on your system. Currently only single-track video encoding is supported, audio support is tbd.\n\n"
		"Movie creation is a 3 step procedure:\n"
		"1. Create a movie and define encoding options via 'CreateMovie'.\n"
		"2. Add video frames to the movie via calls to 'AddFrameToMovie'.\n"
		"3. Finalize and close the movie via a call to 'FinalizeMovie'.\n\n"
		"All following parameters are optional and have reasonable defaults:\n\n"
		"'width' Width of movie video frames in pixels. Defaults to width of window 'windowPtr'.\n"
		"'height' Height of movie video frames in pixels. Defaults to height of window 'windowPtr'.\n"
		"'frameRate' Playback framerate of movie. Defaults to 30 fps. Technically this is not the "
		"playback framerate but the granularity in 1/frameRate seconds with which the duration of "
		"a single movie frame can be specified. When you call 'AddFrameToMovie', there's an optional "
		"parameter 'frameDuration' which defaults to one. The parameter defines the display duration "
		"of that frame as the fraction 'frameDuration' / 'frameRate' seconds, so 'frameRate' defines "
		"the denominator of that term. However, for a default 'frameDuration' of one, this is equivalent "
		"to the 'frameRate' of the movie, at least if you leave everything at defaults.\n\n"
		"'movieoptions' a textstring which allows to define additional parameters via keyword=parm pairs. "
		"Keywords unknown to a certain implementation or codec will be silently ignored:\n"
		"EncodingQuality=x Set encoding quality to value x, in the range 0.0 for lowest movie quality to "
		"1.0 for highest quality. Default is 0.5 = normal quality. 1.0 usually provides lossless encoding.\n"
		"CodecFOURCCId=id FOURCC id. The FOURCC of a desired video codec as a number. Defaults to H.264 codec.\n"
		"Choice of codec and quality defines a tradeoff between filesize, quality, processing demand and speed, "
		"as well as on which target devices you'll be able to play your movie.\n"
		"CodecFOURCC=xxxx FOURCC as a four character text string instead of a number.\n"
		"\n";

	static char seeAlsoString[] = "FinalizeMovie AddFrameToMovie CloseMovie PlayMovie GetMovieImage GetMovieTimeIndex SetMovieTimeIndex";
	
	PsychWindowRecordType					*windowRecord;
	char                                    *moviefile;
	char									*movieOptions;
	int                                     moviehandle = -1;
	double                                  framerate = 30.0;
	int                                     width;
	int                                     height;
	char									defaultOptions[2] = "";
	
	// All sub functions should have these two lines
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none);};
	
	PsychErrorExit(PsychCapNumInputArgs(6));            // Max. 6 input args.
	PsychErrorExit(PsychRequireNumInputArgs(2));        // Min. 2 input args required.
	PsychErrorExit(PsychCapNumOutputArgs(1));           // Max. 1 output args.
	
	// Get the window record from the window record argument and get info from the window record
	PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
	// Only onscreen windows allowed:
	if(!PsychIsOnscreenWindow(windowRecord)) {
		PsychErrorExitMsg(PsychError_user, "CreateMovie called on something else than an onscreen window.");
	}
	
	// Get the movie name string:
	moviefile = NULL;
	PsychAllocInCharArg(2, kPsychArgRequired, &moviefile);
	
	// Get the optional size:
	// Default Width and Height of movie frames is derived from size of window:
	width = PsychGetWidthFromRect(windowRecord->rect);
	height = PsychGetHeightFromRect(windowRecord->rect);
	PsychCopyInIntegerArg(3, kPsychArgOptional, &width);
	PsychCopyInIntegerArg(4, kPsychArgOptional, &height);
	
	// Get the optional framerate:
	PsychCopyInDoubleArg(5, kPsychArgOptional, &framerate);
	
	// Get the optional options string:
	movieOptions = defaultOptions;
	PsychAllocInCharArg(6, kPsychArgOptional, &movieOptions);

	// Create movie of given size and framerate with given options:
	moviehandle = PsychCreateNewMovieFile(moviefile, width, height, framerate, movieOptions);
	if (0 > moviehandle) {
		printf("See http://developer.apple.com/documentation/QuickTime/APIREF/ErrorCodes.htm#//apple_ref/doc/constant_group/Error_Codes.\n\n");
		PsychErrorExitMsg(PsychError_user, "CreateMovie failed for reason mentioned above.");
	}
	
	// Return handle to it:
	PsychCopyOutDoubleArg(1, FALSE, (double) moviehandle);
	
	return(PsychError_none);
}
PsychError SCREENOpenVideoCapture(void) 
{
	PsychWindowRecordType					*windowRecord;
	int                                     deviceIndex;
	int                                     capturehandle = -1;
	double                                  framerate;
	int                                     width;
	int                                     height;
	PsychRectType                           roirectangle;
	Boolean                                 roiassigned;
	int                                     reqdepth = 0;
	int                                     num_dmabuffers = 0;
	int                                     allow_lowperf_fallback = 1;
	char*									moviename;
	int										recordingflags;
	int										engineId;
	
	// All sub functions should have these two lines
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none);};

	PsychErrorExit(PsychCapNumInputArgs(9));            // Max. 9 input args.
	PsychErrorExit(PsychRequireNumInputArgs(1));        // Min. 1 input args required.
	PsychErrorExit(PsychCapNumOutputArgs(1));           // Max. 1 output args.
	
	// Get the window record from the window record argument and get info from the window record
	PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
	// Only onscreen windows allowed:
	if(!PsychIsOnscreenWindow(windowRecord)) {
		PsychErrorExitMsg(PsychError_user, "OpenVideoCapture called on something else than an onscreen window.");
	}
	
	// Get the device index. We default to the first device if none is given:
	deviceIndex=0;
	PsychCopyInIntegerArg(2, FALSE, &deviceIndex);
	
	// Get the optional roi rectangle:
	roiassigned = PsychCopyInRectArg(3, FALSE, roirectangle);
	if (IsPsychRectEmpty(roirectangle)) PsychErrorExitMsg(PsychError_user, "OpenVideoCapture called with invalid (empty) roirectangle argument.");
	
	
	// Query (optional) output texture pixel depth: By default, we take whatever we get from the capture device:
	PsychCopyInIntegerArg(4, FALSE, &reqdepth);
	if (reqdepth<0) PsychErrorExitMsg(PsychError_user, "OpenVideoCapture called with invalid (negative) pixeldepth argument.");
	// Query number of ringbuffers to use. Our default is coded in the OS dependent subroutines.
	PsychCopyInIntegerArg(5, FALSE, &num_dmabuffers);
	if (num_dmabuffers<0) PsychErrorExitMsg(PsychError_user, "OpenVideoCapture called with invalid (negative) numbuffers argument.");
	// Query, if use of low-performance fallback code is allowed if high-perf engine fails:
	PsychCopyInIntegerArg(6, FALSE, &allow_lowperf_fallback);
	if (allow_lowperf_fallback<0) PsychErrorExitMsg(PsychError_user, "OpenVideoCapture called with invalid (negative) allowfallback flag.");
	
	// Query optional moviename for recording the grabbed video into a Quicktime movie file:
	moviename = NULL;
	PsychAllocInCharArg(7, FALSE, &moviename);
	
	// Query optional movie recording flags:
	// 0 = Record video, stream to disk immediately (slower, but unlimited recording duration).
	// 1 = Record video, stream to memory, then at end of recording to disk (limited duration by RAM size, but faster).
	// 2 = Record audio as well.
	recordingflags = 0;
	PsychCopyInIntegerArg(8, FALSE, &recordingflags);
	
	// Copy in optional id of video capture engine to use. We default to the one set via the Screen('Preference', 'DefaultVideocaptureEngine');
	// setting, which by itself defaults to LibDC1394 (type 1) on Linux, and Quicktime/SG (type 0) on all other OSs.
	engineId = PsychPrefStateGet_VideoCaptureEngine();
	PsychCopyInIntegerArg(9, FALSE, &engineId);
	if (engineId<0 || engineId>1)  PsychErrorExitMsg(PsychError_user, "OpenVideoCapture called with invalid 'captureEngineType' argument. Valid are zero and one.");

	// Try to open the capture device and create & initialize a corresponding capture object.
	// A MATLAB handle to the video capture object is returned upon successfull operation.
	if (roiassigned) {
		PsychOpenVideoCaptureDevice(engineId, windowRecord, deviceIndex, &capturehandle, roirectangle, reqdepth, num_dmabuffers, allow_lowperf_fallback, moviename, recordingflags);
	}
	else {
		PsychOpenVideoCaptureDevice(engineId, windowRecord, deviceIndex, &capturehandle, NULL, reqdepth, num_dmabuffers, allow_lowperf_fallback, moviename, recordingflags);
	}
	
	// Upon sucessfull completion, we'll have a valid handle in 'capturehandle'. Return it to Matlab-world:
	PsychCopyOutDoubleArg(1, TRUE, (double) capturehandle);
	
	// Ready!
	return(PsychError_none);
}
PsychError SCREENTextBounds(void)
{
   PsychWindowRecordType  *winRec;
   char			           *textString;
   int                    stringl, i;
	PsychRectType			  resultPsychRect, resultPsychNormRect;
   float                  accumWidth, maxHeight;

    // All subfunctions should have these two lines.  
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    PsychErrorExit(PsychCapNumInputArgs(5));   	
    PsychErrorExit(PsychRequireNumInputArgs(2)); 	
    PsychErrorExit(PsychCapNumOutputArgs(2));  

    //Get the window structure for the onscreen window.
    PsychAllocInWindowRecordArg(1, TRUE, &winRec);
    
    //Get the text string (it is required)
    PsychAllocInCharArg(2, kPsychArgRequired, &textString);

    PsychCopyInDoubleArg(3, kPsychArgOptional, &(winRec->textAttributes.textPositionX));
    PsychCopyInDoubleArg(4, kPsychArgOptional, &(winRec->textAttributes.textPositionY));

	 // Enable GL context of this window - we might need it:
    PsychSetGLContext(winRec);

    // Does the font (== it's display list) need to be build or rebuild, because
    // font name, size or settings have changed?
    // This routine will check it and perform all necessary ops if so...
    PsychOSRebuildFont(winRec);

    // Top-Left bounds of text are current (x,y) position of text drawing cursor:
    resultPsychRect[kPsychLeft] = winRec->textAttributes.textPositionX;
    resultPsychRect[kPsychTop]  = winRec->textAttributes.textPositionY;

    // Compute text x and y increments:
    stringl=strlen(textString);
    accumWidth=0;
    maxHeight=0;
    for (i=0; i<stringl; i++) {
      accumWidth+=winRec->textAttributes.glyphWidth[textString[i]];
      maxHeight=(fabs(winRec->textAttributes.glyphHeight[textString[i]]) > maxHeight) ? fabs(winRec->textAttributes.glyphHeight[textString[i]]) : maxHeight;
    }

    accumWidth*=(PSYCH_SYSTEM == PSYCH_WINDOWS) ? winRec->textAttributes.textSize : 1.0;
    maxHeight*=(PSYCH_SYSTEM == PSYCH_WINDOWS) ? winRec->textAttributes.textSize : 1.0;

    resultPsychRect[kPsychRight]  = winRec->textAttributes.textPositionX + accumWidth;

    // MK: This should work according to spec, but f%$!*g Windows only returns zero values for
	 // for glyphHeight, so maxHeight is always zero :(
    // resultPsychRect[kPsychBottom] = winRec->textAttributes.textPositionY + maxHeight;

    // As fallback, we use this: It gives correct Bottom-Bound for character strings with characters that
    // don't contain descenders. The extra height of characters with descenders is not taken into account.
    resultPsychRect[kPsychBottom] = winRec->textAttributes.textPositionY + winRec->textAttributes.textSize;


    // Compute normalized version which just encodes text bounding box, not text position box:
	 PsychNormalizeRect(resultPsychRect, resultPsychNormRect);

    // Return optional values:
	 PsychCopyOutRectArg(1, FALSE, resultPsychNormRect);
	 PsychCopyOutRectArg(2, FALSE, resultPsychRect);

    // Done.
    return(PsychError_none);
}
PsychError SCREENCreateMovie(void)
{
    static char useString[] = "moviePtr = Screen('CreateMovie', windowPtr, movieFile [, width][, height][, frameRate=30][, movieOptions][, numChannels=4][, bitdepth=8]);";
    static char synopsisString[] =
        "Create a new movie file with filename 'movieFile' and according to given 'movieOptions'.\n"
        "The function returns a handle 'moviePtr' to the file.\n"
        "Currently only single-track video encoding is supported.\n"
        "See 'Screen AddAudioBufferToMovie?' on how to add audio tracks to movies.\n"
        "\n"
        "Movie creation is a 3 step procedure:\n"
        "1. Create a movie and define encoding options via 'CreateMovie'.\n"
        "2. Add video and audio data to the movie via calls to 'AddFrameToMovie' et al.\n"
        "3. Finalize and close the movie via a call to 'FinalizeMovie'.\n\n"
        "All following parameters are optional and have reasonable defaults:\n\n"
        "'width' Width of movie video frames in pixels. Defaults to width of window 'windowPtr'.\n"
        "'height' Height of movie video frames in pixels. Defaults to height of window 'windowPtr'.\n"
        "'frameRate' Playback framerate of movie. Defaults to 30 fps. Technically this is not the "
        "playback framerate but the granularity in 1/frameRate seconds with which the duration of "
        "a single movie frame can be specified. When you call 'AddFrameToMovie', there's an optional "
        "parameter 'frameDuration' which defaults to one. The parameter defines the display duration "
        "of that frame as the fraction 'frameDuration' / 'frameRate' seconds, so 'frameRate' defines "
        "the denominator of that term. However, for a default 'frameDuration' of one, this is equivalent "
        "to the 'frameRate' of the movie, at least if you leave everything at defaults.\n\n"
        "'movieoptions' a textstring which allows to define additional parameters via keyword=parm pairs. "
        "For GStreamer movie writing, you can provide the same options as for GStreamer video recording. "
        "See 'help VideoRecording' for supported options and tips.\n"
        "Keywords unknown to a certain implementation or codec will be silently ignored:\n"
        "EncodingQuality=x Set encoding quality to value x, in the range 0.0 for lowest movie quality to "
        "1.0 for highest quality. Default is 0.5 = normal quality. 1.0 often provides near-lossless encoding.\n"
        "'numChannels' Optional number of image channels to encode: Can be 1, 3 or 4 on OpenGL graphics hardware, "
        "and 3 or 4 on OpenGL-ES hardware. 1 = Red/Grayscale channel only, 3 = RGB, 4 = RGBA. Please note that not "
        "all video codecs can encode pure 1 channel data or RGBA data, ie. an alpha channel. If an unsuitable codec "
        "is selected, movie writing may fail, or unsupported channels (e.g., the alpha channel) may get silently "
        "discarded. It could also happen that a codec which doesn't support 1 channel storage will replicate "
        "the Red/Grayscale data into all three RGB channels, leading to no data loss but increased movie file size. "
        "Default is to request RGBA 4 channel data from the system, encoding to RGBA or RGB, depending on codec.\n"
        "'bitdepth' Optional color/intensity resolution of each channel: Default is 8 bpc, for 8 bit per component "
        "storage. OpenGL graphics hardware, but not OpenGL-ES, also supports 16 bpc image readback. However, not all "
        "codecs can encode with > 8 bpc color/luminance precision, so encoding with 16 bpc may fail or silently reduce "
        "precision to less bits, possibly 8 bpc or less. If you specify the special keyword UsePTB16BPC in 'movieoptions', "
        "then PTB will use its own proprietary 16 bpc format for 1 or 3 channel mode. This format can only be read by "
        "PTB's own movie playback functions, not by other software.\n"
        "In general, embedded OpenGL-ES graphics hardware is more restricted in the type of image data it can return. "
        "Most video codecs are lossy codecs. They will intentionally throw away color or spatial precision of encoded "
        "video to reduce video file size or network bandwidth, often in a way that is not easily perceptible to the "
        "naked eye. If you require high fidelity, make sure to double-check your results for a given codec + parameter "
        "setup, e.g., via encoding + decoding the movie and checking the original data against decoded data.\n"
        "\n";

    static char seeAlsoString[] = "FinalizeMovie AddFrameToMovie CloseMovie PlayMovie GetMovieImage GetMovieTimeIndex SetMovieTimeIndex";

    PsychWindowRecordType                   *windowRecord;
    char                                    *moviefile;
    char                                    *movieOptions;
    int                                     moviehandle = -1;
    double                                  framerate = 30.0;
    int                                     width;
    int                                     height;
    int                                     numChannels, bitdepth;
    char                                    defaultOptions[2] = "";

    // All sub functions should have these two lines
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none);};

    PsychErrorExit(PsychCapNumInputArgs(8));            // Max. 8 input args.
    PsychErrorExit(PsychRequireNumInputArgs(2));        // Min. 2 input args required.
    PsychErrorExit(PsychCapNumOutputArgs(1));           // Max. 1 output args.

    // Get the window record from the window record argument and get info from the window record
    PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
    // Only onscreen windows allowed:
    if(!PsychIsOnscreenWindow(windowRecord)) {
        PsychErrorExitMsg(PsychError_user, "CreateMovie called on something else than an onscreen window.");
    }

    // Get the movie name string:
    moviefile = NULL;
    PsychAllocInCharArg(2, kPsychArgRequired, &moviefile);

    // Get the optional size:
    // Default Width and Height of movie frames is derived from size of window:
    width  = (int) PsychGetWidthFromRect(windowRecord->clientrect);
    height = (int) PsychGetHeightFromRect(windowRecord->clientrect);
    PsychCopyInIntegerArg(3, kPsychArgOptional, &width);
    PsychCopyInIntegerArg(4, kPsychArgOptional, &height);

    // Get the optional framerate:
    PsychCopyInDoubleArg(5, kPsychArgOptional, &framerate);

    // Get the optional options string:
    movieOptions = defaultOptions;
    PsychAllocInCharArg(6, kPsychArgOptional, &movieOptions);

    // Get optional number of channels of movie:
    numChannels = 4;
    PsychCopyInIntegerArg(7, kPsychArgOptional, &numChannels);
    if (numChannels != 1 && numChannels != 3 && numChannels != 4) PsychErrorExitMsg(PsychError_user, "Invalid number of channels 'numChannels' provided. Only 1, 3 or 4 channels allowed!");

    // Get optional bitdepth of movie:
    bitdepth = 8;
    PsychCopyInIntegerArg(8, kPsychArgOptional, &bitdepth);
    if (bitdepth != 8 && bitdepth != 16) PsychErrorExitMsg(PsychError_user, "Invalid 'bitdepth' provided. Only 8 bpc or 16 bpc allowed!");

    // Create movie of given size and framerate with given options:
    moviehandle = PsychCreateNewMovieFile(moviefile, width, height, framerate, numChannels, bitdepth, movieOptions, NULL);
    if (0 > moviehandle) {
        PsychErrorExitMsg(PsychError_user, "CreateMovie failed for reason mentioned above.");
    }

    // Return handle to it:
    PsychCopyOutDoubleArg(1, FALSE, (double) moviehandle);

    return(PsychError_none);
}
PsychError EyelinkCommand(void)
{
	int					i				= 0;
	int					iNumInArgs		= 0;
	int					iStatus			= -1;
	PsychArgFormatType	psychArgType	= PsychArgType_none;
	double				fTempValue		= 0.0;
	char				*pstrTemp		= NULL;
	char				*pstrFormat		= NULL;
	void				**pArgs			= NULL;
	char				strCommand[256];
	
	// Clear strings
	memset(strCommand, 0, sizeof(strCommand));

	// Add help strings
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	
	// Output help if asked
	if(PsychIsGiveHelp()) {
		PsychGiveHelp();
		return(PsychError_none);
	}

	// Check arguments
	PsychErrorExit(PsychRequireNumInputArgs(1));
//	PsychErrorExit(PsychCapNumOutputArgs(0));
	PsychErrorExit(PsychCapNumOutputArgs(1));
	
	// Verify eyelink is up and running
	EyelinkSystemIsConnected();
	EyelinkSystemIsInitialized();

	// Alloc and grab the input format string
	PsychAllocInCharArg(1, TRUE, &pstrFormat);
	iNumInArgs = PsychGetNumInputArgs();   

	// Alloc and grab input args
	if (iNumInArgs > 1) {
		pArgs = (void **)mxMalloc((iNumInArgs-1) * sizeof(char *));
		// loop over the args
		for (i = 2; i <= iNumInArgs; i++) {
			psychArgType = PsychGetArgType(i);
			switch(psychArgType) {
				case PsychArgType_double:
					if ((PsychGetArgM(i) == 1) && (PsychGetArgN(i) == 1)) {
						PsychCopyInDoubleArg(i, TRUE, &fTempValue);
						pArgs[i-2] = (void *) (int) fTempValue; 
					} else {
						PsychGiveHelp();
						return(PsychError_user);
					}
					break;
				case PsychArgType_char:
					pArgs[i-2] = NULL;
					PsychAllocInCharArg(i, TRUE, &pstrTemp);
					pArgs[i-2] = pstrTemp;
					break;
				default:
					PsychGiveHelp();
					return(PsychError_user);
					break;
			} 
		}
	}
	
	// Build eyelink command and execute
	vsprintf(strCommand, pstrFormat, (va_list)pArgs);
	iStatus = eyecmd_printf(strCommand);
	if (pArgs != NULL) {
		mxFree(pArgs);
	}
	
	// Copy out the command result
	PsychCopyOutDoubleArg(1, FALSE, iStatus);
   
	return(PsychError_none);
}