PsychError SCREENglPoint(void)  
{
	
	PsychColorType			color;
	double					*xPosition, *yPosition, dotSize;
	PsychWindowRecordType	*windowRecord;
	int						whiteValue;
	psych_bool					isArgThere;
    
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous arguments
	PsychErrorExit(PsychCapNumInputArgs(5));   //The maximum number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(0));  //The maximum number of outputs

	//get the window record from the window record argument and get info from the window record
	PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
        
	//Get the color argument or use the default, then coerce to the form determened by the window depth.  
	isArgThere=PsychCopyInColorArg(kPsychUseDefaultArgPosition, FALSE, &color);
		if(!isArgThere){
			whiteValue=PsychGetWhiteValueFromWindow(windowRecord);
			PsychLoadColorStruct(&color, kPsychIndexColor, whiteValue ); //index mode will coerce to any other.
		}

 	PsychCoerceColorMode( &color);
        
	//get the x and y position values. 
	PsychAllocInDoubleArg(3, TRUE,  &xPosition);
	PsychAllocInDoubleArg(4, TRUE,  &yPosition);
	dotSize=1;	//set the default
	PsychCopyInDoubleArg(5, FALSE, &dotSize);

	// Enable this windowRecords framebuffer as current drawingtarget:
	PsychSetDrawingTarget(windowRecord);

	// Set default draw shader:
	PsychSetShader(windowRecord, -1);

	PsychUpdateAlphaBlendingFactorLazily(windowRecord);
	PsychSetGLColor(&color, windowRecord);
	glEnable(GL_POINT_SMOOTH);
	glPointSize((float)dotSize);
	glBegin(GL_POINTS);
		glVertex2d( (GLdouble)*xPosition, *yPosition);
	glEnd();
	glDisable(GL_POINT_SMOOTH);
	glPointSize(1);

	// Mark end of drawing op. This is needed for single buffered drawing:
	PsychFlushGL(windowRecord);

 	//All psychfunctions require this.
	return(PsychError_none);
}
PsychError SCREENgluDisk(void)  
{
	
	PsychColorType			color;
	double					*xPosition, *yPosition, dotSize;
	PsychWindowRecordType	*windowRecord;
	int						depthValue, whiteValue, colorPlaneSize, numColorPlanes;
	boolean					isArgThere;
	GLUquadricObj			*diskQuadric;
    
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous arguments
	PsychErrorExit(PsychCapNumInputArgs(5));   //The maximum number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(0));  //The maximum number of outputs

	//get the window record from the window record argument and get info from the window record
	PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
	
	//Get the depth from the window, we need this to interpret the color argument.
	depthValue=PsychGetWindowDepthValueFromWindowRecord(windowRecord);
	numColorPlanes=PsychGetNumPlanesFromDepthValue(depthValue);
	colorPlaneSize=PsychGetColorSizeFromDepthValue(depthValue);

	//Get the color argument or use the default, then coerce to the form determened by the window depth.  
	isArgThere=PsychCopyInColorArg(kPsychUseDefaultArgPosition, FALSE, &color);
		if(!isArgThere){
			whiteValue=PsychGetWhiteValueFromDepthValue(depthValue);
			PsychLoadColorStruct(&color, kPsychIndexColor, whiteValue ); //index mode will coerce to any other.
		}
 	PsychCoerceColorModeFromSizes(numColorPlanes, colorPlaneSize, &color);
        
	//get the x and y position values. 
	PsychAllocInDoubleArg(3, TRUE,  &xPosition);
	PsychAllocInDoubleArg(4, TRUE,  &yPosition);
	dotSize=1;	//set the default
	PsychCopyInDoubleArg(5, FALSE, &dotSize);

	//Set the color and draw the rect.  Note that all GL drawing commands should be sandwiched between 
	PsychSetGLContext(windowRecord);
	PsychUpdateAlphaBlendingFactorLazily(windowRecord);
	PsychSetGLColor(&color, depthValue);
	glPushMatrix();
	glTranslated(*xPosition,*yPosition,0);
	diskQuadric=gluNewQuadric();
	gluDisk(diskQuadric, 0, dotSize, 30, 30);
	gluDeleteQuadric(diskQuadric);
	glPopMatrix();
	//PsychGLRect(rect);
	PsychFlushGL(windowRecord);  //OS X: This does nothing if we are multi buffered, otherwise it glFlushes
       
 	//All psychfunctions require this.
	return(PsychError_none);
}
PsychError SCREENDrawLine(void)  
{
	
	PsychColorType					color;
	PsychWindowRecordType			*windowRecord;
	int								depthValue, whiteValue, colorPlaneSize, numColorPlanes;
	boolean							isArgThere;
	double							sX, sY, dX, dY, penSize;
    
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous arguments
	PsychErrorExit(PsychCapNumInputArgs(7));   //The maximum number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(0));  //The maximum number of outputs

	//get the window record from the window record argument and get info from the window record
	PsychAllocInWindowRecordArg(1, kPsychArgRequired, &windowRecord);
	
	//Get the depth from the window, we need this to interpret the color argument.
	depthValue=PsychGetWindowDepthValueFromWindowRecord(windowRecord);
	numColorPlanes=PsychGetNumPlanesFromDepthValue(depthValue);
	colorPlaneSize=PsychGetColorSizeFromDepthValue(depthValue);

	//Get the color argument or use the default, then coerce to the form determened by the window depth.  
	isArgThere=PsychCopyInColorArg(2, FALSE, &color);
	if(!isArgThere){
		whiteValue=PsychGetWhiteValueFromDepthValue(depthValue);
		PsychLoadColorStruct(&color, kPsychIndexColor, whiteValue ); //index mode will coerce to any other.
	}
 	PsychCoerceColorModeFromSizes(numColorPlanes, colorPlaneSize, &color);
        
	//get source and destination X and Y values
	PsychCopyInDoubleArg(3, kPsychArgRequired, &sX);
	PsychCopyInDoubleArg(4, kPsychArgRequired, &sY);
	PsychCopyInDoubleArg(5, kPsychArgRequired, &dX);
	PsychCopyInDoubleArg(6, kPsychArgRequired, &dY);
	
	//get and set the pen size
	penSize=1;
	PsychCopyInDoubleArg(7, kPsychArgOptional, &penSize);
	glLineWidth((GLfloat)penSize);
	
	//draw the rect
	PsychSetGLContext(windowRecord); 
	PsychUpdateAlphaBlendingFactorLazily(windowRecord);
	PsychSetGLColor(&color, depthValue);
	glBegin(GL_LINES);
		glVertex2d((GLdouble)sX, (GLdouble)sY);
		glVertex2d((GLdouble)dX, (GLdouble)dY);
	glEnd();
	
	return(PsychError_none);
}
/* PsychPrepareRenderBatch()
 *
 * Perform setup for a batch of render requests for a specific primitive. Some 2D Screen
 * drawing commands allow to specify a list of primitives to draw instead of only a single
 * one. E.g. 'DrawDots' allows to draw thousands of dots with one single DrawDots command.
 * This helper routine is called by such batch-capable commands. It checks which input arguments
 * are provided and if its a single one or multiple ones. It sets up the rendering pipe accordingly,
 * performing required conversion steps. The actual drawing routine just needs to perform primitive
 * specific code.
 */
void PsychPrepareRenderBatch(PsychWindowRecordType *windowRecord, int coords_pos, int* coords_count, double** xy, int colors_pos, int* colors_count, int* colorcomponent_count, double** colors, unsigned char** bytecolors, int sizes_pos, int* sizes_count, double** size)
{
	PsychColorType							color;
	int                                     m,n,p,mc,nc,pc;
	int                                     i, nrpoints, nrsize;
	psych_bool                              isArgThere, isdoublecolors, isuint8colors, usecolorvector, needxy;
	double									*tmpcolors, *pcolors, *tcolors;
	double									convfactor, whiteValue;

	needxy = (coords_pos > 0) ? TRUE: FALSE;
	coords_pos = abs(coords_pos);
	colors_pos = abs(colors_pos);
	sizes_pos = abs(sizes_pos);
	
	// Get mandatory or optional xy coordinates argument
	isArgThere = PsychIsArgPresent(PsychArgIn, coords_pos);
	if(!isArgThere && needxy) {
		PsychErrorExitMsg(PsychError_user, "No position argument supplied");
	}
	
	if (isArgThere) {
		PsychAllocInDoubleMatArg(coords_pos, TRUE, &m, &n, &p, xy);
		if(p!=1 || (m!=*coords_count && (m*n)!=*coords_count)) {
			printf("PTB-ERROR: Coordinates must be a %i tuple or a %i rows vector.\n", *coords_count, *coords_count);
			PsychErrorExitMsg(PsychError_user, "Invalid format for coordinate specification.");
		}
		
		if (m!=1) {
			nrpoints=n;
			*coords_count = n;
		}
		else {
			// Special case: 1 row vector provided for single argument.
			nrpoints=1;
			*coords_count = 1;
		}
	}
	else {
		nrpoints = 0;
		*coords_count = 0;
	}
	
	if (size) {
		// Get optional size argument
		isArgThere = PsychIsArgPresent(PsychArgIn, sizes_pos);
		if(!isArgThere){
			// No size provided: Use a default size of 1.0:
			*size = (double *) PsychMallocTemp(sizeof(double));
			*size[0] = 1;
			nrsize=1;
		} else {
			PsychAllocInDoubleMatArg(sizes_pos, TRUE, &m, &n, &p, size);
			if(p!=1) PsychErrorExitMsg(PsychError_user, "Size must be a scalar or a vector with one column or row");
			nrsize=m*n;
			if (nrsize!=nrpoints && nrsize!=1 && *sizes_count!=1) PsychErrorExitMsg(PsychError_user, "Size vector must contain one size value per item.");
		}
		
		*sizes_count = nrsize;
	}	

	// Check if color argument is provided:
	isArgThere = PsychIsArgPresent(PsychArgIn, colors_pos);        
	if(!isArgThere) {
		// No color argument provided - Use defaults:
		whiteValue=PsychGetWhiteValueFromWindow(windowRecord);
		PsychLoadColorStruct(&color, kPsychIndexColor, whiteValue ); //index mode will coerce to any other.
		usecolorvector=false;
	}
	else {
		// Some color argument provided. Check first, if it's a valid color vector:
		isdoublecolors = PsychAllocInDoubleMatArg(colors_pos, kPsychArgAnything, &mc, &nc, &pc, colors);
		isuint8colors  = PsychAllocInUnsignedByteMatArg(colors_pos, kPsychArgAnything, &mc, &nc, &pc, bytecolors);
		
		// Do we have a color vector, aka one element per vertex?
		if((isdoublecolors || isuint8colors) && pc==1 && mc!=1 && nc==nrpoints && nrpoints>1) {
			// Looks like we might have a color vector... ... Double-check it:
			if (mc!=3 && mc!=4) PsychErrorExitMsg(PsychError_user, "Color vector must be a 3 or 4 row vector");
			// Yes. colors is a valid pointer to it.
			usecolorvector=true;
			
			if (isdoublecolors) {
				if (fabs(windowRecord->colorRange)!=1) {
					// We have to loop through the vector and divide all values by windowRecord->colorRange, so the input values
					// 0-colorRange get mapped to the range 0.0-1.0, as OpenGL expects values in range 0-1 when
					// a color vector is passed in Double- or Float format.
					// This is inefficient, as it burns some cpu-cycles, but necessary to keep color
					// specifications consistent in the PTB - API.
					convfactor = 1.0 / fabs(windowRecord->colorRange);
					tmpcolors=PsychMallocTemp(sizeof(double) * nc * mc);
					pcolors = *colors;
					tcolors = tmpcolors;
					for (i=0; i<(nc*mc); i++) {
						*(tcolors++)=(*pcolors++) * convfactor;
					}
				}
				else {
					// colorRange is == 1 --> No remapping needed as colors are already in proper range!
					// Just setup pointer to our unaltered input color vector:
					tmpcolors=*colors;
				}
				
				*colors = tmpcolors;
			}
			else {
				// Color vector in uint8 format. Nothing to do.
			}
		}
		else {
			// No color vector provided: Check for a single valid color triplet or quadruple:
			usecolorvector=false;
			isArgThere=PsychCopyInColorArg(colors_pos, TRUE, &color);                
		}
	}
	
	// Enable this windowRecords framebuffer as current drawingtarget:
	PsychSetDrawingTarget(windowRecord);
	
	// Setup default drawshader:
	PsychSetShader(windowRecord, -1);
	
	// Setup alpha blending properly:
	PsychUpdateAlphaBlendingFactorLazily(windowRecord);
	
 	// Setup common color for all objects if no color vector has been provided:
	if (!usecolorvector) {
		PsychCoerceColorMode(&color);
		PsychSetGLColor(&color, windowRecord);
		*colors_count = 1;
	}
	else {
		*colors_count = nc;
	}
	*colorcomponent_count = mc;
		
	return;
}
void PsychRenderArc(unsigned int mode)
{
        PsychColorType			color;
        PsychRectType                   rect;
        double				*startAngle, *arcAngle, *penWidth, *penHeight;
	PsychWindowRecordType           *windowRecord;
	int				depthValue, whiteValue, colorPlaneSize, numColorPlanes;
	double                          dotSize;
        boolean				isArgThere;
	GLUquadric                      *diskQuadric = NULL;


	//get the window record from the window record argument and get info from the window record
	PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
	
	//Get the depth from the window, we need this to interpret the color argument.
	depthValue=PsychGetWindowDepthValueFromWindowRecord(windowRecord);
	numColorPlanes=PsychGetNumPlanesFromDepthValue(depthValue);
	colorPlaneSize=PsychGetColorSizeFromDepthValue(depthValue);

	//Get the color argument or use the default, then coerce to the form determened by the window depth.  
	isArgThere=PsychCopyInColorArg(kPsychUseDefaultArgPosition, FALSE, &color);
        if(!isArgThere){
                whiteValue=PsychGetWhiteValueFromDepthValue(depthValue);
                PsychLoadColorStruct(&color, kPsychIndexColor, whiteValue ); //index mode will coerce to any other.
        }
 	PsychCoerceColorModeFromSizes(numColorPlanes, colorPlaneSize, &color);
        
        // Get the rect to which the object should be inscribed: Default is "full screen"
        PsychMakeRect(rect, 0, 0, PsychGetWidthFromRect(windowRecord->rect), PsychGetHeightFromRect(windowRecord->rect));
        PsychCopyInRectArg(3, FALSE, rect);
        double w=PsychGetWidthFromRect(rect);
        double h=PsychGetHeightFromRect(rect);
        double cx, cy, aspect;
        PsychGetCenterFromRectAbsolute(rect, &cx, &cy);
        if (w==0 || h==0) PsychErrorExitMsg(PsychError_user, "Invalid rect (width or height equals zero) provided!");
        
	// Get start angle: 
	PsychAllocInDoubleArg(4, TRUE,  &startAngle);
	PsychAllocInDoubleArg(5, TRUE,  &arcAngle);

        if (mode==2) {
            // Get pen width and height:
            penWidth=NULL;
            penHeight=NULL;
            PsychAllocInDoubleArg(6, FALSE,  &penWidth);
            PsychAllocInDoubleArg(7, FALSE,  &penHeight);
            // Check if penWidth and penHeight spec'd. If so, they
            // need to be equal:
            if (penWidth && penHeight && (*penWidth!=*penHeight)) {
                PsychErrorExitMsg(PsychError_user, "penWidth and penHeight must be equal on OS-X if both are specified!");
            }
            dotSize=1;
            if (penWidth) dotSize = *penWidth;
            if (penHeight) dotSize = *penHeight;
        }
        
        // Setup OpenGL context:
	PsychSetGLContext(windowRecord);
	PsychUpdateAlphaBlendingFactorLazily(windowRecord);
	PsychSetGLColor(&color, depthValue);
        
        // Backup our modelview matrix:
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();

	// Position disk at center of rect:
        glTranslated(cx, cy, 0);
        
        // Scale in order to fit to rect in case w!=h:
        glScaled(1.0, -h/w, 1.0);
        
        // Draw filled partial disk:
        diskQuadric=gluNewQuadric();
        
        switch (mode) {
            case 1: // One pixel thin arc: InnerRadius = OuterRadius - 1
                gluPartialDisk(diskQuadric, (w/2) - 1.0, w/2, w, 2, *startAngle, *arcAngle);
                break;
            case 2: // dotSize thick arc:  InnerRadius = OuterRadius - dotsize
                gluPartialDisk(diskQuadric, (dotSize < (w/2)) ? (w/2) - dotSize : 0, w/2, w, 2, *startAngle, *arcAngle);
                break;
            case 3: // Filled arc:
                gluPartialDisk(diskQuadric, 0, w/2, w, 1, *startAngle, *arcAngle);
                break;
        }

	gluDeleteQuadric(diskQuadric);
	
        // Restore old matrix:
        glPopMatrix();

	return;
}
PsychError SCREENOpenWindow(void) 

{
    int						screenNumber, numWindowBuffers, stereomode, multiSample, imagingmode;
    PsychRectType 			rect, screenrect;
    PsychColorType			color;
    PsychColorModeType  	mode; 
    boolean					isArgThere, settingsMade, didWindowOpen, useAGL;
    PsychScreenSettingsType	screenSettings;
    PsychWindowRecordType	*windowRecord;
    double dVals[4];
    PsychDepthType			specifiedDepth, possibleDepths, currentDepth, useDepth;
	int dummy1;
	double dummy2, dummy3, dummy4;
	Boolean EmulateOldPTB = PsychPrefStateGet_EmulateOldPTB();
    
	//just for debugging
    //if (PSYCH_DEBUG == PSYCH_ON) printf("Entering SCREENOpen\n");

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

    //cap the number of inputs
    PsychErrorExit(PsychCapNumInputArgs(8));   //The maximum number of inputs
    PsychErrorExit(PsychCapNumOutputArgs(2));  //The maximum number of outputs

    //get the screen number from the windowPtrOrScreenNumber.  This also checks to make sure that the specified screen exists.  
    PsychCopyInScreenNumberArg(kPsychUseDefaultArgPosition, TRUE, &screenNumber);
    if(screenNumber==-1)
        PsychErrorExitMsg(PsychError_user, "The specified onscreen window has no ancestral screen."); 

    /*
      The depth checking is ugly because of this stupid depth structure stuff.  
      Instead get a descriptor of the current video settings, change the depth field,
      and pass it to a validate function wich searches a list of valid video modes for the display.
      There seems to be no point in checking the depths alone because the legality of a particular
      depth depends on the other settings specified below.  Its probably best to wait until we have
      digested all settings and then test the full mode, declarin an invalid
      mode and not an invalid pixel size.  We could notice when the depth alone is specified 
      and in that case issue an invalid depth value.
     */  

    //find the PixelSize first because the color specifier depends on the screen depth.  
    PsychInitDepthStruct(&currentDepth);  //get the current depth
    PsychGetScreenDepth(screenNumber, &currentDepth);
    PsychInitDepthStruct(&possibleDepths); //get the possible depths
    PsychGetScreenDepths(screenNumber, &possibleDepths);

    #if PSYCH_SYSTEM == PSYCH_OSX || PSYCH_SYSTEM == PSYCH_WINDOWS
       // MK Experimental Hack: Add the special depth values 64 and 128 to the depth struct. This should 
       // allows for 16 bpc, 32 bpc floating point color buffers on the latest ATI and NVidia hardware.
	   // "Should" means: It doesn't really work with any current driver, but we leave the testcode in
	   // in the hope for future OS and driver releases ;-)
       // Unfortunately at this point of the init sequence, we are not able
       // to check if these formats are supported by the hardware. Ugly ugly ugly...
       PsychAddValueToDepthStruct(64, &possibleDepths);
       PsychAddValueToDepthStruct(128, &possibleDepths);
    #endif

//    #if PSYCH_SYSTEM == PSYCH_OSX || PSYCH_SYSTEM == PSYCH_LINUX
		// On MacOS/X and Linux with ATI Radeon X1000/HD2000/HD3000 hardware and the special
		// kernel support driver installed, we should be able to configure the hardwares
		// framebuffers into ABGR2101010 mode, ie. 2 bits alpha, 10 bpc for red, green, blue.
		// This needs support from the imaging pipeline, or manually converted stimuli, as
		// the GPU doesn't format pixel data properly, only the CRTC scans out in that format.
		// Anyway, allow this setting on OS/X and Linux:
		
		// Update: Some FireGL cards (2008 and later) claim to support this on MS-Windows. Enable
		// this option on Windows as well, so it is at least testable:
		PsychAddValueToDepthStruct(30, &possibleDepths);
//    #endif


    PsychInitDepthStruct(&specifiedDepth); //get the requested depth and validate it.  
    isArgThere = PsychCopyInSingleDepthArg(4, FALSE, &specifiedDepth);

    PsychInitDepthStruct(&useDepth);
    if(isArgThere){ //if the argument is there check that the screen supports it...
        if(!PsychIsMemberDepthStruct(&specifiedDepth, &possibleDepths))
            PsychErrorExit(PsychError_invalidDepthArg);
        else
            PsychCopyDepthStruct(&useDepth, &specifiedDepth);
    }else //otherwise use the default
        PsychCopyDepthStruct(&useDepth, &currentDepth);

    // Initialize the rect argument to the screen rectangle:
    PsychGetScreenRect(screenNumber, rect); 	//get the rect describing the screen bounds.  This is the default Rect.  

    // Override it with a user supplied rect, if one was supplied:
    isArgThere=PsychCopyInRectArg(kPsychUseDefaultArgPosition, FALSE, rect );
    if (IsPsychRectEmpty(rect)) PsychErrorExitMsg(PsychError_user, "OpenWindow called with invalid (empty) rect argument.");

	if (PSYCH_SYSTEM == PSYCH_OSX) {
		// OS/X system: Need to decide if we use a Carbon window + AGL
		// or a fullscreen context with CGL:
		
		// Default to AGL, switch to CGL if below constraints are met:
		useAGL = TRUE;
	
		// Window rect provided which has a different size than screen?

		// We do not use windowed mode if the provided window rectangle either
		// matches the target screens rectangle (and therefore its exact size)
		// or its screens global rectangle.
		PsychGetScreenRect(screenNumber, screenrect);
		if (PsychMatchRect(screenrect, rect)) useAGL=FALSE;
		PsychGetGlobalScreenRect(screenNumber, screenrect);
		if (PsychMatchRect(screenrect, rect)) useAGL=FALSE;

		// Override for use on f$%#$Fd OS/X 10.5.3 - 10.5.6 with NVidia GF 8800 GPU's:
		if (PsychPrefStateGet_ConserveVRAM() & kPsychUseAGLCompositorForFullscreenWindows) useAGL = TRUE;
	}
	else {
		// Non OS/X system: Do not use AGL ;-)
		useAGL = FALSE;
	}
	
    //find the number of specified buffers. 

    //OS X:	The number of backbuffers is not a property of the display mode but an attribute of the pixel format.
    //		Therefore the value is held by a window record and not a screen record.    

    numWindowBuffers=2;	
    PsychCopyInIntegerArg(5,FALSE,&numWindowBuffers);
    if(numWindowBuffers < 1 || numWindowBuffers > kPsychMaxNumberWindowBuffers) PsychErrorExit(PsychError_invalidNumberBuffersArg);

    // MK: Check for optional spec of stereoscopic display: 0 (the default) = monoscopic viewing.
    // 1 == Stereo output via OpenGL built-in stereo facilities: This will drive any kind of
    // stereo display hardware that is directly supported by MacOS-X.
    // 2/3 == Stereo output via compressed frame output: Only one backbuffer is used for both
    // views: The left view image is put into the top-half of the screen, the right view image
    // is put into the bottom half of the screen. External hardware demangles this combi-image
    // again into two separate images. CrystalEyes seems to be able to do this. One looses half
    // of the vertical resolution, but potentially gains refresh rate...
    // Future PTB version may include different stereo algorithms with an id > 1, e.g., 

    // anaglyph stereo, interlaced stereo, ...

    stereomode=0;
    PsychCopyInIntegerArg(6,FALSE,&stereomode);
    if(stereomode < 0 || stereomode > 10) PsychErrorExitMsg(PsychError_user, "Invalid stereomode provided (Valid between 0 and 10).");
	if (stereomode!=0 && EmulateOldPTB) PsychErrorExitMsg(PsychError_user, "Sorry, stereo display functions are not supported in OS-9 PTB emulation mode.");

    multiSample=0;
    PsychCopyInIntegerArg(7,FALSE,&multiSample);
    if(multiSample < 0) PsychErrorExitMsg(PsychError_user, "Invalid multisample value provided (Valid are positive numbers >= 0).");
	if (multiSample!=0 && EmulateOldPTB) PsychErrorExitMsg(PsychError_user, "Sorry, anti-aliasing functions are not supported in OS-9 PTB emulation mode.");

	imagingmode=0;
    PsychCopyInIntegerArg(8,FALSE,&imagingmode);
    if(imagingmode < 0) PsychErrorExitMsg(PsychError_user, "Invalid imaging mode provided (See 'help PsychImagingMode' for usage info).");
	if (imagingmode!=0 && EmulateOldPTB) PsychErrorExitMsg(PsychError_user, "Sorry, imaging pipeline functions are not supported in OS-9 PTB emulation mode.");
	
	// We require use of the imaging pipeline if stereomode for dualwindow display is requested.
	// This makes heavy use of FBO's and blit operations, so imaging pipeline is needed.
	if (stereomode==kPsychDualWindowStereo) {
		// Dual window stereo requested, but imaging pipeline not enabled. Enable it:
		imagingmode|= kPsychNeedFastBackingStore;
		if (PsychPrefStateGet_Verbosity()>3) printf("PTB-INFO: Trying to enable imaging pipeline for dual-window stereo display mode...\n");
	}
	
    //set the video mode to change the pixel size.  TO DO: Set the rect and the default color  
    PsychGetScreenSettings(screenNumber, &screenSettings);    
    PsychInitDepthStruct(&(screenSettings.depth));
    PsychCopyDepthStruct(&(screenSettings.depth), &useDepth);

    // Here is where all the work goes on:

    // If the screen is not already captured then to that:
    if(!PsychIsScreenCaptured(screenNumber) && !useAGL) {
        PsychCaptureScreen(screenNumber);

		// We disable the call to PsychSetScreenSettings here: Its not useful, as it
		// could only change color depth - which is something we don't want to do anyway here.
		// If people want to change displays settings, they should use Screen('Resolution') instead,
		// which is a more clever interface to PsychSetScreenSettings().
		
        // settingsMade=PsychSetScreenSettings(screenNumber, &screenSettings);
        //Capturing the screen and setting its settings always occur in conjunction
        //There should be a check above to see if the display is captured and openWindow is attempting to chang
        //the bit depth
    }

#if PSYCH_SYSTEM == PSYCH_WINDOWS
    // On M$-Windows we currently only support - and therefore require >= 30 bpp color depth.
    if (PsychGetScreenDepthValue(screenNumber) < 30) {
		// Display running at less than 30 bpp. OpenWindow will fail on M$-Windows anyway, so let's abort
		// now.

		// Output warning text:
        printf("PTB-ERROR: Your display screen %i is not running at the required color depth of at least 30 bit.\n", screenNumber);
        printf("PTB-ERROR: The current setting is %i bit color depth..\n", PsychGetScreenDepthValue(screenNumber));
        printf("PTB-ERROR: This will not work on Microsoft Windows operating systems.\n");
        printf("PTB-ERROR: Please use the 'Display settings' control panel of Windows to change the color depth to\n");
        printf("PTB-ERROR: 32 bits per pixel ('True color' or 'Highest' setting) and then retry. It may be neccessary\n");
        printf("PTB-ERROR: to restart Matlab after applying the change...\n");
        fflush(NULL);

		// Release the captured screen:
		PsychRestoreScreenSettings(screenNumber);
		PsychReleaseScreen(screenNumber);

        // Reset master assignment to prepare possible further dual-window config operations:
		sharedContextWindow = NULL;

		// Abort with Matlab error:
		PsychErrorExitMsg(PsychError_user, "Insufficient color depth setting for display device (smaller than 30 bpp).");
    }

#endif

    //if (PSYCH_DEBUG == PSYCH_ON) printf("Entering PsychOpenOnscreenWindow\n");
    PsychCopyDepthStruct(&(screenSettings.depth), &useDepth);
	
	// Create the onscreen window and perform initialization of everything except
	// imaging pipeline and a few other special quirks. If sharedContextWindow is non-NULL,
	// the new window will share its OpenGL context ressources with sharedContextWindow.
	// This is typically used for dual-window stereo mode. Btw. If imaging pipeline is really
	// active, we force multiSample to zero: This way the system backbuffer / pixelformat
	// is enabled without multisampling support, as we do all the multisampling stuff ourselves
	// within the imaging pipeline with multisampled drawbuffer FBO's...
    didWindowOpen=PsychOpenOnscreenWindow(&screenSettings, &windowRecord, numWindowBuffers, stereomode, rect, ((imagingmode==0 || imagingmode==kPsychNeedFastOffscreenWindows) ? multiSample : 0), sharedContextWindow);
    if (!didWindowOpen) {
        if (!useAGL) {
			PsychRestoreScreenSettings(screenNumber);
			PsychReleaseScreen(screenNumber);
		}

		// Reset master assignment to prepare possible further dual-window config operations:
		sharedContextWindow = NULL;

        // We use this dirty hack to exit with an error, but without printing
        // an error message. The specific error message has been printed in
        // PsychOpenOnscreenWindow() already..
        PsychErrMsgTxt("");
    }

    // Sufficient display depth for full alpha-blending and such?
    if (PsychGetScreenDepthValue(screenNumber) < 24) {
        // Nope. Output a little warning.
        printf("PTB-WARNING: Your display screen %i is not running at 24 bit color depth or higher.\n", screenNumber);
        printf("PTB-WARNING: The current setting is %i bit color depth..\n", PsychGetScreenDepthValue(screenNumber));
        printf("PTB-WARNING: This could cause failure to work correctly or visual artifacts in stimuli\n");
        printf("PTB-WARNING: that involve Alpha-Blending. It can also cause drastically reduced color resolution\n");
        printf("PTB-WARNING: for your stimuli! Please try to switch your display to 'True Color' (Windows)\n");
        printf("PTB-WARNING: our 'Millions of Colors' (MacOS-X) to get rid of this warning and the visual artifacts.\n");
        fflush(NULL);
    }
    
	// Define clear color: This depends on the color range of our onscreen window...
    isArgThere=PsychCopyInColorArg(kPsychUseDefaultArgPosition, FALSE, &color); //get from user
    if(!isArgThere) PsychLoadColorStruct(&color, kPsychIndexColor, PsychGetWhiteValueFromWindow(windowRecord)); //or use the default
    PsychCoerceColorMode(&color);

	// Special setup code for dual window stereomode:
	if (stereomode == kPsychDualWindowStereo) {
		if (sharedContextWindow) {
			// This is creation & setup of the slave onscreen window, ie. the one
			// representing the right-eye view. This window doesn't do much. It
			// is not used or referenced in the users experiment script. It receives
			// its final image content during Screen('Flip') operation of the master
			// onscreen window, then gets flipped in sync with the master window.
			
			// Ok, we already have the slave window open and it shares its OpenGL context
			// with the master window. Reset its internal reference to the master:
			windowRecord->slaveWindow = NULL;
			
			// Reset imagingmode for this window prior to imaging pipeline setup. This
			// window is totally passive so it doesn't need the imaging pipeline.
			imagingmode = 0;
						
			// Assign this window to the master window as a slave:
			sharedContextWindow->slaveWindow = windowRecord;
			
			// Reset master assignment to prepare possible further dual-window config operations:
			sharedContextWindow = NULL;

			// Activate the IdentitiyBlitChain for the slave window and add a single identity blit
			// operation to it: This is needed in PsychPreFlipOperations() for final copy of stimulus
			// image into this slave window:
			PsychPipelineAddBuiltinFunctionToHook(windowRecord, "IdentityBlitChain", "Builtin:IdentityBlit", INT_MAX, "");
			PsychPipelineEnableHook(windowRecord, "IdentityBlitChain");

			if (PsychPrefStateGet_Verbosity()>3) printf("PTB-INFO: Created master-slave window relationship for dual-window stereo display mode...\n");

			// Special config finished. The master-slave combo should work from now on...
		}
		else {
			// This is initial setup & creation of the master onscreen window, ie. the one
			// representing the left-eye view and doing all the heavy work, acting as a
			// proxy for both windows.
			
			// Not much to do here. Just store its windowRecord as a reference for creation
			// of the slave window. We'll need it for that purpose...
			sharedContextWindow = windowRecord;
		}
	}

	// Set special half-width flag for window if we are either in a dual-display/dual-view stereo mode or if
	// if is requested as part of the imagingMode flag. This will cause PTB 2D drawing routines and window size
	// query routines etc. to return an effective window width or window rect only half the real width.
	if (windowRecord->stereomode==kPsychFreeFusionStereo || windowRecord->stereomode==kPsychFreeCrossFusionStereo || (imagingmode & kPsychHalfWidthWindow)) {
		windowRecord->specialflags = windowRecord->specialflags | kPsychHalfWidthWindow;
		imagingmode = imagingmode & (~kPsychHalfWidthWindow);
	}

	// Similar handling for windows of half the real height, except that none of our built-in stereo modes requires these,
	// so this is only done on request from external code via the imagingmode flag kPsychHalfHeightWindow.
	// One use of this is when using interleaved line stereo mode (PsychImaging(...'InterleavedLineStereo')) where windows
	// only have a useable net height of half their physical height:
	if (imagingmode & kPsychHalfHeightWindow) {
		windowRecord->specialflags = windowRecord->specialflags | kPsychHalfHeightWindow;
		imagingmode = imagingmode & (~kPsychHalfHeightWindow);
	}

	// Initialize internal image processing pipeline if requested:
	PsychInitializeImagingPipeline(windowRecord, imagingmode, multiSample);
	
	// On OS-X, if we are in quad-buffered frame sequential stereo mode, we automatically generate
	// blue-line-sync style sync lines for use with stereo shutter glasses. We don't do this
	// by default on Windows or Linux: These systems either don't have stereo capable hardware,
	// or they have some and its drivers already take care of sync signal generation.
	if ((PSYCH_SYSTEM == PSYCH_OSX) && (windowRecord->stereomode==kPsychOpenGLStereo)) {
		if (PsychPrefStateGet_Verbosity()>3) printf("PTB-INFO: Enabling internal blue line sync renderer for quad-buffered stereo...\n");
		PsychPipelineAddBuiltinFunctionToHook(windowRecord, "LeftFinalizerBlitChain", "Builtin:RenderStereoSyncLine", INT_MAX, "");
		PsychPipelineEnableHook(windowRecord, "LeftFinalizerBlitChain");		
		PsychPipelineAddBuiltinFunctionToHook(windowRecord, "RightFinalizerBlitChain", "Builtin:RenderStereoSyncLine", INT_MAX, "");
		PsychPipelineEnableHook(windowRecord, "RightFinalizerBlitChain");		
	}

	// Activate new onscreen window for userspace drawing: If imaging pipeline is active, this
	// will bind the correct rendertargets for the first time:
	PsychSetDrawingTarget(windowRecord);

    // Set the clear color and perform a backbuffer-clear:
    PsychConvertColorToDoubleVector(&color, windowRecord, windowRecord->clearColor);
	PsychGLClear(windowRecord);

    // Mark end of drawing op. This is needed for single buffered drawing:
    PsychFlushGL(windowRecord);

    // Make sure no OpenGL errors happened up to this point:
    PsychTestForGLErrors();

    // If we are in logo-startup mode (former blue-screen mode) and double-buffering
    // is enabled, then do an initial bufferswap & clear, so the display starts in
    // the user selected background color instead of staying at the blue screen or
    // logo display until the Matlab script first calls 'Flip'.
    if ((PsychPrefStateGet_VisualDebugLevel()>=4) && numWindowBuffers>=2) {
      // Do immediate bufferswap by an internal call to Screen('Flip'). This will also
	  // take care of clearing the backbuffer in preparation of first userspace drawing
	  // commands and such...
	  PsychFlipWindowBuffers(windowRecord, 0, 0, 0, 0, &dummy1, &dummy2, &dummy3, &dummy4);
      // Display now shows background color, so user knows that PTB's 'OpenWindow'
      // procedure is successfully finished.
    }

    PsychTestForGLErrors();

    //Return the window index and the rect argument.
    PsychCopyOutDoubleArg(1, FALSE, windowRecord->windowIndex);

	// rect argument needs special treatment in stereo mode:
	PsychMakeRect(&rect, windowRecord->rect[kPsychLeft], windowRecord->rect[kPsychTop],
					windowRecord->rect[kPsychLeft] + PsychGetWidthFromRect(windowRecord->rect)/((windowRecord->specialflags & kPsychHalfWidthWindow) ? 2 : 1),
					windowRecord->rect[kPsychTop] + PsychGetHeightFromRect(windowRecord->rect)/((windowRecord->specialflags & kPsychHalfHeightWindow) ? 2 : 1));

    PsychCopyOutRectArg(2, FALSE, rect);

    return(PsychError_none);   
}
PsychError SCREENFillPoly(void)  
{	
	PsychColorType				color;
	PsychWindowRecordType		*windowRecord;
	double						whiteValue;
	int							i, mSize, nSize, pSize;
	psych_bool					isArgThere;
	double						*pointList;
	double						isConvex;
	int							j,k;
	int							flag;
	double						z;
	
	combinerCacheSlot = 0;
	combinerCacheSize = 0;
	combinerCache = NULL;
	
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous arguments
	PsychErrorExit(PsychCapNumInputArgs(4));   //The maximum number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(0));  //The maximum number of outputs
	
	//get the window record from the window record argument and get info from the window record
	PsychAllocInWindowRecordArg(1, kPsychArgRequired, &windowRecord);
	
	//Get the color argument or use the default, then coerce to the form determened by the window depth.  
	isArgThere=PsychCopyInColorArg(2, FALSE, &color);
	if(!isArgThere){
		whiteValue=PsychGetWhiteValueFromWindow(windowRecord);
		PsychLoadColorStruct(&color, kPsychIndexColor, whiteValue ); //index mode will coerce to any other.
	}
 	PsychCoerceColorMode( &color);
	
	//get the list of pairs and validate.  
	PsychAllocInDoubleMatArg(3, kPsychArgRequired, &mSize, &nSize, &pSize, &pointList);
	if(nSize!=2) PsychErrorExitMsg(PsychError_user, "Width of pointList must be 2");
	if(mSize<3)  PsychErrorExitMsg(PsychError_user, "Polygons must consist of at least 3 points; M dimension of pointList was < 3!");
	if(pSize>1)  PsychErrorExitMsg(PsychError_user, "pointList must be a 2D matrix, not a 3D matrix!");
	
	isConvex = -1;
	PsychCopyInDoubleArg(4, kPsychArgOptional, &isConvex);
	
    // On non-OpenGL1/2 we always force isConvex to zero, so the GLU tesselator is
    // always used. This because the tesselator only emits GL_TRIANGLES and GL_TRIANGLE_STRIP
    // and GL_TRIANGLE_FANS primitives which are supported on all current OpenGL API's, whereas
    // or "classic" fast-path needs GL_POLYGONS, which are only supported on classic OpenGL1/2:
    if (!PsychIsGLClassic(windowRecord)) isConvex = 0;

	// Enable this windowRecords framebuffer as current drawingtarget:
	PsychSetDrawingTarget(windowRecord);
	
	// Set default drawshader:
	PsychSetShader(windowRecord, -1);
	
	PsychUpdateAlphaBlendingFactorLazily(windowRecord);		 
	PsychSetGLColor(&color, windowRecord);
	
	///////// Test for convexity ////////
	// This algorithm checks, if the polygon is definitely convex, or not.
	// We take the slow-path, if polygon is non-convex or if we can't prove
	// that it is convex.
	//
	// Algorithm adapted from: http://astronomy.swin.edu.au/~pbourke/geometry/clockwise/
	// Which was written by Paul Bourke, 1998.
	//
	// -> This webpage explains the mathematical principle behind the test and provides
	// a C-Source file which has been adapted for use here.
	//	
	if (isConvex == -1) {
		flag = 0;
		for (i=0; i < mSize; i++) {
			j = (i + 1) % mSize;
			k = (i + 2) % mSize;
			z  = (pointList[j] - pointList[i]) * (pointList[k+mSize] - pointList[j+mSize]);
			z -= (pointList[j+mSize] - pointList[i+mSize]) * (pointList[k] - pointList[j]);
			
			if (z < 0) {
				flag |= 1;
			}
			else if (z > 0) {
				flag |= 2;
			}
			
			if (flag == 3) {
				// This is definitely a CONCAVE polygon --> not Convex --> Take slow but safe path.
				break;
			}
		}
		
		if (flag!=0 && flag!=3) {
			// This is a convex polygon --> Take fast path.
			isConvex = 1;
		}
		else {
			// This is a complex polygon --> can't determine if it is convex or not --> Take slow but safe path.
			isConvex = 0;
		}
	}
			
	////// Switch between fast path and slow path, depending on convexity of polygon:
	if (isConvex > 0) {
		// Convex, non-self-intersecting polygon - Take the fast-path:
		glBegin(GL_POLYGON);
		for(i=0;i<mSize;i++) glVertex2d((GLdouble)pointList[i], (GLdouble)pointList[i+mSize]);
		glEnd();
	}
	else {
		// Possibly concave and/or self-intersecting polygon - At least we couldn't prove it is convex.
		// Take the slow, but safe, path using GLU-Tesselators to break it up into a couple of convex, simple
		// polygons:
		
		// Create and initialize a new GLU-Tesselator object, if needed:
		if (NULL == tess) {
			// Create tesselator:
			tess = gluNewTess();
			if (NULL == tess) PsychErrorExitMsg(PsychError_outofMemory, "Out of memory condition in Screen('FillPoly')! Not enough space.");

			// Assign our callback-functions:
			gluTessCallback(tess, GLU_TESS_BEGIN, GLUTESSCBCASTER PsychtcbBegin);
			gluTessCallback(tess, GLU_TESS_VERTEX, GLUTESSCBCASTER PsychtcbVertex);
			gluTessCallback(tess, GLU_TESS_END, GLUTESSCBCASTER PsychtcbEnd);
			gluTessCallback(tess, GLU_TESS_COMBINE, GLUTESSCBCASTER PsychtcbCombine);

			// Define all tesselated polygons to lie in the x-y plane:
			gluTessNormal(tess, 0, 0, 1);
		}

		// We need to hold the values in a temporary array:
		if (tempvsize < mSize) {
			tempvsize = ((mSize / 1000) + 1) * 1000;
			tempv = (double*) realloc((void*) tempv, sizeof(double) * 3 * tempvsize);
			if (NULL == tempv) PsychErrorExitMsg(PsychError_outofMemory, "Out of memory condition in Screen('FillPoly')! Not enough space.");
		}

		// Now submit our Polygon for tesselation:
		gluTessBeginPolygon(tess, NULL);
		gluTessBeginContour(tess);

		for(i=0; i < mSize; i++) {
			tempv[i*3]=(GLdouble) pointList[i];
			tempv[i*3+1]=(GLdouble) pointList[i+mSize];
			tempv[i*3+2]=0;
			gluTessVertex(tess, (GLdouble*) &(tempv[i*3]), (void*) &(tempv[i*3]));
		}
		
		// Process, finalize and render it by calling our callback-functions:
		gluTessEndContour(tess);
		gluTessEndPolygon (tess);
		
		// Done with drawing the filled polygon. (Slow-Path)
	}
	
	// Mark end of drawing op. This is needed for single buffered drawing:
	PsychFlushGL(windowRecord);
	
	// printf("CombinerCalls %i out of %i allocated.\n", combinerCacheSlot, combinerCacheSize);

	return(PsychError_none);
}
PsychError SCREENOpenWindow(void) 

{
    int					screenNumber, numWindowBuffers, stereomode, multiSample, imagingmode;
    PsychRectType 			rect;
    PsychColorType			color;
    PsychColorModeType  		mode; 
    boolean				isArgThere, settingsMade, didWindowOpen;
    PsychScreenSettingsType		screenSettings;
    PsychWindowRecordType		*windowRecord;
    double dVals[4];
    PsychDepthType		specifiedDepth, possibleDepths, currentDepth, useDepth;
	int dummy1;
	double dummy2, dummy3, dummy4;
	Boolean EmulateOldPTB = PsychPrefStateGet_EmulateOldPTB();
    
	//just for debugging
    //if (PSYCH_DEBUG == PSYCH_ON) printf("Entering SCREENOpen\n");

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

    //cap the number of inputs
    PsychErrorExit(PsychCapNumInputArgs(8));   //The maximum number of inputs
    PsychErrorExit(PsychCapNumOutputArgs(2));  //The maximum number of outputs

    //get the screen number from the windowPtrOrScreenNumber.  This also checks to make sure that the specified screen exists.  
    PsychCopyInScreenNumberArg(kPsychUseDefaultArgPosition, TRUE, &screenNumber);
    if(screenNumber==-1)
        PsychErrorExitMsg(PsychError_user, "The specified offscreen window has no ancestral screen."); 

    /*
      The depth checking is ugly because of this stupid depth structure stuff.  
      Instead get a descriptor of the current video settings, change the depth field,
      and pass it to a validate function wich searches a list of valid video modes for the display.
      There seems to be no point in checking the depths alone because the legality of a particular
      depth depends on the other settings specified below.  Its probably best to wait until we have
      digested all settings and then test the full mode, declarin an invalid
      mode and not an invalid pixel size.  We could notice when the depth alone is specified 
      and in that case issue an invalid depth value.
     */  

    //find the PixelSize first because the color specifier depends on the screen depth.  
    PsychInitDepthStruct(&currentDepth);  //get the current depth
    PsychGetScreenDepth(screenNumber, &currentDepth);
    PsychInitDepthStruct(&possibleDepths); //get the possible depths
    PsychGetScreenDepths(screenNumber, &possibleDepths);

    #if PSYCH_SYSTEM == PSYCH_OSX || PSYCH_SYSTEM == PSYCH_WINDOWS
       // MK Experimental Hack: Add the special depth values 30, 64 and 128 to the depth struct. This allows for
       // 10 bpc color buffers and 16 bpc, 32 bpc floating point color buffers on the latest ATI
       // and NVidia hardware. Unfortunately at this point of the init sequence, we are not able
       // to check if these formats are supported by the hardware. Ugly ugly ugly...
       PsychAddValueToDepthStruct(30, &possibleDepths);
       PsychAddValueToDepthStruct(64, &possibleDepths);
       PsychAddValueToDepthStruct(128, &possibleDepths);
    #endif

    PsychInitDepthStruct(&specifiedDepth); //get the requested depth and validate it.  
    isArgThere = PsychCopyInSingleDepthArg(4, FALSE, &specifiedDepth);

    PsychInitDepthStruct(&useDepth);
    if(isArgThere){ //if the argument is there check that the screen supports it...
        if(!PsychIsMemberDepthStruct(&specifiedDepth, &possibleDepths))
            PsychErrorExit(PsychError_invalidDepthArg);
        else
            PsychCopyDepthStruct(&useDepth, &specifiedDepth);
    }else //otherwise use the default
        PsychCopyDepthStruct(&useDepth, &currentDepth);

    //find the rect.
    PsychGetScreenRect(screenNumber, rect); 	//get the rect describing the screen bounds.  This is the default Rect.  

    // Override it with a user supplied rect, if one was supplied:
    isArgThere=PsychCopyInRectArg(kPsychUseDefaultArgPosition, FALSE, rect );
    if (IsPsychRectEmpty(rect)) PsychErrorExitMsg(PsychError_user, "OpenWindow called with invalid (empty) rect argument.");

    //find the number of specified buffers. 

    //OS X:	The number of backbuffers is not a property of the display mode but an attribute of the pixel format.
    //		Therefore the value is held by a window record and not a screen record.    

    numWindowBuffers=2;	
    PsychCopyInIntegerArg(5,FALSE,&numWindowBuffers);
    if(numWindowBuffers < 1 || numWindowBuffers > kPsychMaxNumberWindowBuffers) PsychErrorExit(PsychError_invalidNumberBuffersArg);

    // MK: Check for optional spec of stereoscopic display: 0 (the default) = monoscopic viewing.
    // 1 == Stereo output via OpenGL built-in stereo facilities: This will drive any kind of
    // stereo display hardware that is directly supported by MacOS-X.
    // 2/3 == Stereo output via compressed frame output: Only one backbuffer is used for both
    // views: The left view image is put into the top-half of the screen, the right view image
    // is put into the bottom half of the screen. External hardware demangles this combi-image
    // again into two separate images. CrystalEyes seems to be able to do this. One looses half
    // of the vertical resolution, but potentially gains refresh rate...
    // Future PTB version may include different stereo algorithms with an id > 1, e.g., 

    // anaglyph stereo, interlaced stereo, ...

    stereomode=0;
    PsychCopyInIntegerArg(6,FALSE,&stereomode);
    if(stereomode < 0 || stereomode > 9) PsychErrorExitMsg(PsychError_user, "Invalid stereomode provided (Valid between 0 and 9).");
	if (stereomode!=0 && EmulateOldPTB) PsychErrorExitMsg(PsychError_user, "Sorry, stereo display functions are not supported in OS-9 PTB emulation mode.");

    multiSample=0;
    PsychCopyInIntegerArg(7,FALSE,&multiSample);
    if(multiSample < 0) PsychErrorExitMsg(PsychError_user, "Invalid multisample value provided (Valid are positive numbers >= 0).");
	if (multiSample!=0 && EmulateOldPTB) PsychErrorExitMsg(PsychError_user, "Sorry, anti-aliasing functions are not supported in OS-9 PTB emulation mode.");

	imagingmode=0;
    PsychCopyInIntegerArg(8,FALSE,&imagingmode);
    if(imagingmode < 0) PsychErrorExitMsg(PsychError_user, "Invalid imaging mode provided (See 'help PsychImagingMode' for usage info).");
	if (imagingmode!=0 && EmulateOldPTB) PsychErrorExitMsg(PsychError_user, "Sorry, imaging pipeline functions are not supported in OS-9 PTB emulation mode.");
	
    //set the video mode to change the pixel size.  TO DO: Set the rect and the default color  
    PsychGetScreenSettings(screenNumber, &screenSettings);    
    PsychInitDepthStruct(&(screenSettings.depth));
    PsychCopyDepthStruct(&(screenSettings.depth), &useDepth);

    // Here is where all the work goes on:

    // If the screen is not already captured then to that:
    if(~PsychIsScreenCaptured(screenNumber)) {
        PsychCaptureScreen(screenNumber);

        settingsMade=PsychSetScreenSettings(screenNumber, &screenSettings);
        //Capturing the screen and setting its settings always occur in conjunction
        //There should be a check above to see if the display is captured and openWindow is attempting to chang
        //the bit depth
    }

#if PSYCH_SYSTEM == PSYCH_WINDOWS
    // On M$-Windows we currently only support - and therefore require >= 30 bpp color depth.
    if (PsychGetScreenDepthValue(screenNumber) < 30) {
      // Display running at less than 30 bpp. OpenWindow will fail on M$-Windows anyway, so let's abort
      // now.

      // Release the captured screen:
        PsychReleaseScreen(screenNumber);

	// Output warning text:
        printf("PTB-ERROR: Your display screen %i is not running at the required color depth of at least 30 bit.\n", screenNumber);
        printf("PTB-ERROR: The current setting is %i bit color depth..\n", PsychGetScreenDepthValue(screenNumber));
        printf("PTB-ERROR: This will not work on Microsoft Windows operating systems.\n");
        printf("PTB-ERROR: Please use the 'Display settings' control panel of Windows to change the color depth to\n");
        printf("PTB-ERROR: 32 bits per pixel ('True color' or 'Highest' setting) and then retry. It may be neccessary\n");
        printf("PTB-ERROR: to restart Matlab after applying the change...\n");
        fflush(NULL);

	// Abort with Matlab error:
	PsychErrorExitMsg(PsychError_user, "Insufficient color depth setting for display device (smaller than 30 bpp).");
    }

#endif

    //if (PSYCH_DEBUG == PSYCH_ON) printf("Entering PsychOpenOnscreenWindow\n");
    PsychCopyDepthStruct(&(screenSettings.depth), &useDepth);
    didWindowOpen=PsychOpenOnscreenWindow(&screenSettings, &windowRecord, numWindowBuffers, stereomode, rect, multiSample);

    if (!didWindowOpen) {
        PsychReleaseScreen(screenNumber);

        // We use this dirty hack to exit with an error, but without printing
        // an error message. The specific error message has been printed in
        // PsychOpenOnscreenWindow() already..
        PsychErrMsgTxt("");
    }

    // Sufficient display depth for full alpha-blending and such?
    if (PsychGetScreenDepthValue(screenNumber) < 24) {
        // Nope. Output a little warning.
        printf("PTB-WARNING: Your display screen %i is not running at 24 bit color depth or higher.\n", screenNumber);
        printf("PTB-WARNING: The current setting is %i bit color depth..\n", PsychGetScreenDepthValue(screenNumber));
        printf("PTB-WARNING: This could cause failure to work correctly or visual artifacts in stimuli\n");
        printf("PTB-WARNING: that involve Alpha-Blending. It can also cause drastically reduced color resolution\n");
        printf("PTB-WARNING: for your stimuli! Please try to switch your display to 'True Color' (Windows)\n");
        printf("PTB-WARNING: our 'Millions of Colors' (MacOS-X) to get rid of this warning and the visual artifacts.\n");
        fflush(NULL);
    }
    
	// Define clear color: This depends on the color range of our onscreen window...
    isArgThere=PsychCopyInColorArg(kPsychUseDefaultArgPosition, FALSE, &color); //get from user
    if(!isArgThere) PsychLoadColorStruct(&color, kPsychIndexColor, PsychGetWhiteValueFromWindow(windowRecord)); //or use the default
    PsychCoerceColorMode(&color);

	// Initialize internal image processing pipeline if requested:
	PsychInitializeImagingPipeline(windowRecord, imagingmode);
	
	// On OS-X, if we are int quad-buffered frame sequential stereo mode, we automatically generate
	// blue-line-sync style sync lines for use with stereo shutter glasses. We don't do this
	// by default on Windows or Linux: These systems either don't have stereo capable hardware,
	// or they have some and its drivers already take care of sync signal generation.
	if ((PSYCH_SYSTEM == PSYCH_OSX) && (windowRecord->stereomode==kPsychOpenGLStereo)) {
		if (PsychPrefStateGet_Verbosity()>3) printf("PTB-INFO: Enabling internal blue line sync renderer for quad-buffered stereo...\n");
		PsychPipelineAddBuiltinFunctionToHook(windowRecord, "LeftFinalizerBlitChain", "Builtin:RenderStereoSyncLine", TRUE, "");
		PsychPipelineEnableHook(windowRecord, "LeftFinalizerBlitChain");		
		PsychPipelineAddBuiltinFunctionToHook(windowRecord, "RightFinalizerBlitChain", "Builtin:RenderStereoSyncLine", TRUE, "");
		PsychPipelineEnableHook(windowRecord, "RightFinalizerBlitChain");		
	}

	// Activate new onscreen window for userspace drawing: If imaging pipeline is active, this
	// will bind the correct rendertargets for the first time:
    PsychSetGLContext(windowRecord);
	PsychSetDrawingTarget(windowRecord);

    // Set the clear color and perform a backbuffer-clear:
    PsychConvertColorToDoubleVector(&color, windowRecord, dVals);
    glClearColor(dVals[0], dVals[1], dVals[2], dVals[3]);
    glClear(GL_COLOR_BUFFER_BIT);

    // Mark end of drawing op. This is needed for single buffered drawing:
    PsychFlushGL(windowRecord);

    // Make sure no OpenGL errors happened up to this point:
    PsychTestForGLErrors();

    // If we are in logo-startup mode (former blue-screen mode) and double-buffering
    // is enabled, then do an initial bufferswap & clear, so the display starts in
    // the user selected background color instead of staying at the blue screen or
    // logo display until the Matlab script first calls 'Flip'.
    if ((PsychPrefStateGet_VisualDebugLevel()>=4) && numWindowBuffers>=2) {
      // Do immediate bufferswap by an internal call to Screen('Flip'). This will also
	  // take care of clearing the backbuffer in preparation of first userspace drawing
	  // commands and such...
	  PsychFlipWindowBuffers(windowRecord, 0, 0, 0, 0, &dummy1, &dummy2, &dummy3, &dummy4);
      // Display now shows background color, so user knows that PTB's 'OpenWindow'
      // procedure is successfully finished.
    }

    PsychTestForGLErrors();

    //Return the window index and the rect argument.
    PsychCopyOutDoubleArg(1, FALSE, windowRecord->windowIndex);

	 // rect argument needs special treatment in stereo mode:
	 if (windowRecord->stereomode==kPsychFreeFusionStereo || windowRecord->stereomode==kPsychFreeCrossFusionStereo) {
			// Special case for stereo: Only half the real window width:
			PsychMakeRect(&rect, windowRecord->rect[kPsychLeft],windowRecord->rect[kPsychTop],
							  windowRecord->rect[kPsychLeft] + PsychGetWidthFromRect(windowRecord->rect)/2,windowRecord->rect[kPsychBottom]);
	 }
	 else {
			// Normal case:
			PsychMakeRect(&rect, windowRecord->rect[kPsychLeft],windowRecord->rect[kPsychTop],windowRecord->rect[kPsychRight],windowRecord->rect[kPsychBottom]);
	 }
    PsychCopyOutRectArg(2, FALSE, rect);

    return(PsychError_none);   
}
PsychError SCREENOpenWindow(void) 

{

    int					screenNumber, numWindowBuffers, stereomode;

    PsychRectType 			rect;

    PsychColorType			color;

    PsychColorModeType  		mode; 

    boolean				isArgThere, settingsMade, didWindowOpen;

    PsychScreenSettingsType		screenSettings;

    PsychWindowRecordType		*windowRecord;

    

    PsychDepthType		specifiedDepth, possibleDepths, currentDepth, useDepth;

    

    //just for debugging

    //printf("Entering SCREENOpen\n");

    

    //all sub functions should have these two lines

    PsychPushHelp(useString, synopsisString, seeAlsoString);

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

    

    //cap the number of inputs

    PsychErrorExit(PsychCapNumInputArgs(6));   //The maximum number of inputs

    PsychErrorExit(PsychCapNumOutputArgs(2));  //The maximum number of outputs

    

    //get the screen number from the windowPtrOrScreenNumber.  This also checks to make sure that the specified screen exists.  

    PsychCopyInScreenNumberArg(kPsychUseDefaultArgPosition, TRUE, &screenNumber);

    if(screenNumber==-1)

        PsychErrorExitMsg(PsychError_user, "The specified offscreen window has no ancestral screen."); 

    

    /*

        The depth checking is ugly because of this stupid depth structure stuff.  

     Instead get a descriptor of the current video settings, change the depth field,

     and pass it to a validate function wich searches a list of valid video modes for the display.

     

     There seems to be no point in checking the depths alone because the legality of a particular

     depth depends on the other settings specified below.  Its probably best to wait until we have

     digested all settings and then test the full mode, declarin an invalid

     mode and not an invalid pixel size.  We could notice when the depth alone is specified 

     and in that case issue an invalid depth value.

     */  

    //find the PixelSize first because the color specifier depends on the screen depth.  

    PsychInitDepthStruct(&currentDepth);  //get the current depth

    PsychGetScreenDepth(screenNumber, &currentDepth);

    PsychInitDepthStruct(&possibleDepths); //get the possible depths

    PsychGetScreenDepths(screenNumber, &possibleDepths);

    PsychInitDepthStruct(&specifiedDepth); //get the requested depth and validate it.  

    isArgThere = PsychCopyInSingleDepthArg(4, FALSE, &specifiedDepth);

    PsychInitDepthStruct(&useDepth);

    if(isArgThere){ //if the argument is there check that the screen supports it...

        if(!PsychIsMemberDepthStruct(&specifiedDepth, &possibleDepths))

            PsychErrorExit(PsychError_invalidDepthArg);

        else

            PsychCopyDepthStruct(&useDepth, &specifiedDepth);

    }else //otherwise use the default

        PsychCopyDepthStruct(&useDepth, &currentDepth);

    

    //find the color.  We do this here because the validity of this argument depends on the depth.

    isArgThere=PsychCopyInColorArg(kPsychUseDefaultArgPosition, FALSE, &color); //get from user

    if(!isArgThere)

        PsychLoadColorStruct(&color, kPsychIndexColor, PsychGetWhiteValueFromDepthStruct(&useDepth)); //or use the default

    mode=PsychGetColorModeFromDepthStruct(&useDepth);

    PsychCoerceColorMode(mode, &color);  //transparent if mode match, error exit if invalid conversion.

    

    //find the rect.

    PsychGetScreenRect(screenNumber, rect); 	//get the rect describing the screen bounds.  This is the default Rect.  

    if(!kPsychAllWindowsFull)

        isArgThere=PsychCopyInRectArg(kPsychUseDefaultArgPosition, FALSE, rect );

    

    //find the number of specified buffers. 

    //OS X:	The number of backbuffers is not a property of the display mode but an attribute of the pixel format.

    //		Therefore the value is held by a window record and not a screen record.    

    numWindowBuffers=2;	

    PsychCopyInIntegerArg(5,FALSE,&numWindowBuffers);

    if(numWindowBuffers < 1 || numWindowBuffers > kPsychMaxNumberWindowBuffers)

        PsychErrorExit(PsychError_invalidNumberBuffersArg);

    

    // MK: Check for optional spec of stereoscopic display: 0 (the default) = monoscopic viewing.
    // 1 == Stereo output via OpenGL built-in stereo facilities: This will drive any kind of
    // stereo display hardware that is directly supported by MacOS-X.
    // 2/3 == Stereo output via compressed frame output: Only one backbuffer is used for both
    // views: The left view image is put into the top-half of the screen, the right view image
    // is put into the bottom half of the screen. External hardware demangles this combi-image
    // again into two separate images. CrystalEyes seems to be able to do this. One looses half
    // of the vertical resolution, but potentially gains refresh rate...
    // Future PTB version may include different stereo algorithms with an id > 1, e.g., 

    // anaglyph stereo, interlaced stereo, ...

    stereomode=0;

    PsychCopyInIntegerArg(6,FALSE,&stereomode);

    if(stereomode < 0 || stereomode > 1) PsychErrorExitMsg(PsychError_user, "Invalid stereomode provided (Valid between 0 and 9).");

    

    //set the video mode to change the pixel size.  TO DO: Set the rect and the default color  

    PsychGetScreenSettings(screenNumber, &screenSettings);    

    PsychInitDepthStruct(&(screenSettings.depth));

    PsychCopyDepthStruct(&(screenSettings.depth), &useDepth);

    

    //Here is where all the work goes on

    //if the screen is not already captured then to that

    if(~PsychIsScreenCaptured(screenNumber)){

        PsychCaptureScreen(screenNumber);

        settingsMade=PsychSetScreenSettings(screenNumber, &screenSettings); 

        //Capturing the screen and setting its settings always occur in conjunction.

        //There should be a check above to see if the display is captured and openWindow is attempting to change

        //the bit depth.

    }

    didWindowOpen=PsychOpenOnscreenWindow(&screenSettings, &windowRecord, numWindowBuffers, stereomode);

    if(!didWindowOpen){

        PsychReleaseScreen(screenNumber);

        // We use this dirty hack to exit with an error, but without printing

        // an error message. The specific error message has been printed in

        // PsychOpenOnscreenWindow() already...

        PsychErrMsgTxt("");

    }

    

    //create the shadow texture for this window

    PsychCreateTextureForWindow(windowRecord);

    

    //set the alpha blending rule   

    PsychSetGLContext(windowRecord); 

    // glEnable(GL_BLEND);

    // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    //			sFactor		   dFactor



    

    //Return the window index and the rect argument.

    PsychCopyOutDoubleArg(1, FALSE, windowRecord->windowIndex);

    PsychCopyOutRectArg(2, FALSE, rect);

    return(PsychError_none);    

}
示例#10
0
PsychError SCREENDrawLine(void)  
{
	
	PsychColorType					color;
	PsychWindowRecordType			*windowRecord;
	double							whiteValue;
	psych_bool						isArgThere;
	double							sX, sY, dX, dY, penSize;
	float                           linesizerange[2];

	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous arguments
	PsychErrorExit(PsychCapNumInputArgs(7));   //The maximum number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(0));  //The maximum number of outputs

	//get the window record from the window record argument and get info from the window record
	PsychAllocInWindowRecordArg(1, kPsychArgRequired, &windowRecord);
	
	//Get the color argument or use the default, then coerce to the form determened by the window depth.  
	isArgThere=PsychCopyInColorArg(2, FALSE, &color);
	if(!isArgThere){
		whiteValue=PsychGetWhiteValueFromWindow(windowRecord);
		PsychLoadColorStruct(&color, kPsychIndexColor, whiteValue ); //index mode will coerce to any other.
	}

 	PsychCoerceColorMode( &color);
        
	//get source and destination X and Y values
	PsychCopyInDoubleArg(3, kPsychArgRequired, &sX);
	PsychCopyInDoubleArg(4, kPsychArgRequired, &sY);
	PsychCopyInDoubleArg(5, kPsychArgRequired, &dX);
	PsychCopyInDoubleArg(6, kPsychArgRequired, &dY);
	
	//get and set the pen size
	penSize=1;
	PsychCopyInDoubleArg(7, kPsychArgOptional, &penSize);
	
	// Enable this windowRecords framebuffer as current drawingtarget:
	PsychSetDrawingTarget(windowRecord);

	// Set default draw shader:
	PsychSetShader(windowRecord, -1);

    glGetFloatv(GL_LINE_WIDTH_RANGE, (GLfloat*) &linesizerange);
    if (penSize < linesizerange[0] || penSize > linesizerange[1]) {
		printf("PTB-ERROR: You requested a line width of %f units, which is not in the range (%f to %f) supported by your graphics hardware.\n",
			   penSize, linesizerange[0], linesizerange[1]);
		PsychErrorExitMsg(PsychError_user, "Unsupported line width requested.");
	}

	glLineWidth((GLfloat)penSize);

	PsychUpdateAlphaBlendingFactorLazily(windowRecord);
	PsychSetGLColor(&color, windowRecord);
	glBegin(GL_LINES);
		glVertex2d((GLdouble)sX, (GLdouble)sY);
		glVertex2d((GLdouble)dX, (GLdouble)dY);
	glEnd();
	
	glLineWidth((GLfloat) 1);

	// Mark end of drawing op. This is needed for single buffered drawing:
	PsychFlushGL(windowRecord);

	return(PsychError_none);
}
PsychError SCREENOpenOffscreenWindow(void) 
{
    int						screenNumber, depth, targetScreenNumber;
    PsychRectType			rect;
    PsychColorType			color;
    PsychWindowRecordType	*exampleWindowRecord, *windowRecord, *targetWindow;
    psych_bool				wasColorSupplied;
    char*					texturePointer;
    size_t					xSize, ySize, nbytes;
    psych_bool				bigendian;
	GLubyte					*rpb;
    int						ix;
	GLenum					fboInternalFormat;
	psych_bool				needzbuffer;
	psych_bool				overridedepth = FALSE;
	int						usefloatformat = 0;
	int						specialFlags = 0;
	int						multiSample = 0;
	
    // Detect endianity (byte-order) of machine:
    ix=255;
    rpb=(GLubyte*) &ix;
    bigendian = ( *rpb == 255 ) ? FALSE : TRUE;
    ix = 0; rpb = NULL;

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

    //cap the number of inputs
    PsychErrorExit(PsychCapNumInputArgs(6));   //The maximum number of inputs
    PsychErrorExit(PsychCapNumOutputArgs(2));  //The maximum number of outputs

    //1-User supplies a window ptr 2-User supplies a screen number 3-User supplies rect and pixel size
    if(PsychIsWindowIndexArg(1)){
        PsychAllocInWindowRecordArg(1, TRUE, &exampleWindowRecord);
		// Assign normalized copy of example windows rect -- Top-Left corner is always (0,0)
		PsychNormalizeRect(exampleWindowRecord->clientrect, rect);

        // We copy depth only from exampleWindow if it is a offscreen window (=texture). Copying from
        // onscreen windows doesn't make sense, e.g. depth=16 for onscreen means RGBA8 window, but it
        // would map onto a LUMINANCE+ALPHA texture for the offscreen window! We always use 32 bit RGBA8
        // in such a case.
        depth=(PsychIsOffscreenWindow(exampleWindowRecord)) ? exampleWindowRecord->depth : 32;
		// unless it is a FBO backed onscreen window in imaging mode: Then we can use the depth from it.
		if (exampleWindowRecord->imagingMode & kPsychNeedFastBackingStore || exampleWindowRecord->imagingMode & kPsychNeedFastOffscreenWindows) depth = exampleWindowRecord->depth;
        targetScreenNumber=exampleWindowRecord->screenNumber;
        targetWindow=exampleWindowRecord;
    } else if(PsychIsScreenNumberArg(1)){
        PsychCopyInScreenNumberArg(1, TRUE, &screenNumber);
        PsychGetScreenRect(screenNumber, rect);
        depth=32; // Always use RGBA8 in this case! See above...
        targetScreenNumber=screenNumber;
        targetWindow=NULL;
    } else if(PsychIsUnaffiliatedScreenNumberArg(1)){  //that means -1 or maybe also NaN if we add that option.  
        // Default to a depth of 32 bpp:
        depth = 32;
        targetWindow = NULL;
        // Get first open onscreen window as target window:
        PsychFindScreenWindowFromScreenNumber(kPsychUnaffiliatedWindow, &targetWindow);
		if (targetWindow == NULL) PsychErrorExitMsg(PsychError_user, "Could not find any open onscreen window to act as parent for this offscreen window. Open an onscreen window first!");
		targetScreenNumber = targetWindow->screenNumber;
        PsychGetScreenRect(targetScreenNumber, rect);
    } else {
        targetScreenNumber = 0; // Make compiler happy.
        PsychErrorExit(PsychError_invalidNumdex);
    }

    if (targetWindow==NULL) {
        // Get target window of screen:
        PsychFindScreenWindowFromScreenNumber(targetScreenNumber, &targetWindow);
		if (targetWindow == NULL) PsychErrorExitMsg(PsychError_user, "Could not find any open onscreen window to act as parent for this offscreen window. Open an onscreen window first!");
		targetScreenNumber = targetWindow->screenNumber;
    }
    
    //Depth and rect argument supplied as arguments override those inherited from reference screen or window.
    //Note that PsychCopyIn* prefix means that value will not be overwritten if the arguments are not present.
    PsychCopyInRectArg(3,FALSE, rect);
    if (IsPsychRectEmpty(rect)) PsychErrorExitMsg(PsychError_user, "Invalid rect value provided: Empty rects are not allowed.");

	// Copy in optional depth: This gets overriden in many ways if imaging pipeline is on:
    if (PsychCopyInIntegerArg(4,FALSE, &depth)) overridedepth = TRUE;

    // If any of the no longer supported values 0, 1, 2 or 4 is provided, we
    // silently switch to 32 bits per pixel, which is the safest and fastest setting:
    if (depth==0 || depth==1 || depth==2 || depth==4) depth=32;

    // Final sanity check:
	if (!(targetWindow->imagingMode & kPsychNeedFastOffscreenWindows) && !(targetWindow->imagingMode & kPsychNeedFastBackingStore) && (depth==64 || depth==128)) {
      PsychErrorExitMsg(PsychError_user, "Invalid depth value provided. Must be 8 bpp, 16 bpp, 24 bpp or 32 bpp, unless you enable the imaging pipeline, which provides you with more options!");
	}
	
    if (depth!=8 && depth!=16 && depth!=24 && depth!=32 && depth!=64 && depth!=128) {
      PsychErrorExitMsg(PsychError_user, "Invalid depth value provided. Must be 8 bpp, 16 bpp, 24 bpp, 32 bpp, or if imagingmode is enabled also 64 bpp or 128 bpp!");
    }

	// If the imaging pipeline is enabled for the associated onscreen window and fast backing store, aka FBO's
	// is requested, then we only accept depths of at least 32 bit, i.e. RGBA windows. We override any lower
	// precision spec. This is because some common hardware only supports rendering to RGBA textures, not to
	// RGB, LA or Luminance textures.
	if ((targetWindow->imagingMode & kPsychNeedFastBackingStore || targetWindow->imagingMode & kPsychNeedFastOffscreenWindows) && (depth < 32)) depth = 32;

    // Find the color for the window background.  
    wasColorSupplied=PsychCopyInColorArg(kPsychUseDefaultArgPosition, FALSE, &color);
	
	// If none provided, use a proper white-value for this window:
    if(!wasColorSupplied) PsychLoadColorStruct(&color, kPsychIndexColor, PsychGetWhiteValueFromWindow(targetWindow));  

    // Get the optional specialmode flag:
    PsychCopyInIntegerArg(5, FALSE, &specialFlags);

    // OpenGL-ES only supports GL_TEXTURE_2D targets, so enforce these via flags setting 1:
    if (PsychIsGLES(targetWindow)) specialFlags |= 1;

	// This command converts whatever color we got into RGBA format:
    PsychCoerceColorMode(&color);

    // printf("R=%i G=%i B=%i A=%i I=%i", color.value.rgba.r, color.value.rgba.g,color.value.rgba.b,color.value.rgba.a,color.value.index); 
    // First allocate the offscreen window record to store stuff into. If we exit with an error PsychErrorExit() should
    // call PsychPurgeInvalidWindows which will clean up the window record. 
    PsychCreateWindowRecord(&windowRecord);  // This also fills the window index field.

    // This offscreen window is implemented as a Psychtoolbox texture:
    windowRecord->windowType=kPsychTexture;

    // We need to assign the screen number of the onscreen-window, so PsychCreateTexture()
    // can query the size of the screen/onscreen-window...
    windowRecord->screenNumber = targetScreenNumber;

    // Assign the computed depth:
    windowRecord->depth=depth;

	// Default number of channels:
	windowRecord->nrchannels=depth / 8;

    // Assign the computed rect, but normalize it to start with top-left at (0,0):
    PsychNormalizeRect(rect, windowRecord->rect);

    // Client rect of an offscreen window is always == rect of it:
    PsychCopyRect(windowRecord->clientrect, windowRecord->rect);
    
	// Until here no OpenGL commands executed. Now we need a valid context: Set targetWindow
	// as drawing target. This will perform neccessary context-switch and all backbuffer
	// backup/restore/whatever operations to make sure we can do what we want without
	// possibly screwing any offscreen windows and bindings:
	if (PsychIsOnscreenWindow(targetWindow) || PsychIsOffscreenWindow(targetWindow)) {
		// This is a possible on-/offscreen drawingtarget:
		PsychSetDrawingTarget(targetWindow);
	}
	else {
		// This must be a proxy-window object: Can't transition to it!
		
		// But we can safe-reset the current drawingtarget...
		PsychSetDrawingTarget((PsychWindowRecordType*) 0x1);
		
		// ...and then switch to the OpenGL context of the 'targetWindow' proxy object:
		PsychSetGLContext(targetWindow);

		// Ok, framebuffer and bindings are safe and disabled, context is set. We
		// should be safe to continue with the proxy...
	}
	
	// From here on we have a defined context and state. We can detach the drawing target whenever
	// we want, as everything is backed up somewhere for later reinit.
	
	// Create offscreen window either new style as FBO, or old style as texture:
	if ((targetWindow->imagingMode & kPsychNeedFastBackingStore) || (targetWindow->imagingMode & kPsychNeedFastOffscreenWindows)) {
		// Imaging mode for this window enabled: Use new way of creating the offscreen window:
		
		// We safely unbind any FBO bindings and drawingtargets:
		PsychSetDrawingTarget((PsychWindowRecordType*) 0x1);
		
		// Overriden for imagingmode: There we always have 4 channels...
		windowRecord->nrchannels=4;

		// Start off with standard 8 bpc fixed point:
		fboInternalFormat = GL_RGBA8; windowRecord->depth=32; usefloatformat = 0;
		
		// Need 16 bpc fixed point precision?
		if (targetWindow->imagingMode & kPsychNeed16BPCFixed) {
			fboInternalFormat = (targetWindow->gfxcaps & kPsychGfxCapSNTex16) ? GL_RGBA16_SNORM : GL_RGBA16;
			windowRecord->depth=64;
			usefloatformat = 0;
		}
		
		// Need 16 bpc floating point precision?
		if (targetWindow->imagingMode & kPsychNeed16BPCFloat) { fboInternalFormat = GL_RGBA_FLOAT16_APPLE; windowRecord->depth=64; usefloatformat = 1; }
		
		// Need 32 bpc floating point precision?
		if (targetWindow->imagingMode & kPsychNeed32BPCFloat) { fboInternalFormat = GL_RGBA_FLOAT32_APPLE; windowRecord->depth=128; usefloatformat = 2; }
		
		// Override depth value provided?
		if (overridedepth) {
			// Manual depth specified: Override with that depth:
			switch(depth) {
				case 32:
					fboInternalFormat = GL_RGBA8; windowRecord->depth=32; usefloatformat = 0;
				break;

				case 64:
					fboInternalFormat = GL_RGBA_FLOAT16_APPLE; windowRecord->depth=64; usefloatformat = 1;
					// Need fallback for lack of float 16 support?
					if (!(targetWindow->gfxcaps & kPsychGfxCapFPTex16) && !PsychIsGLES(targetWindow)) {
						// Yes. Try 16 bit signed normalized texture instead:
						if (PsychPrefStateGet_Verbosity() > 4)
							printf("PTB-INFO:OpenOffscreenWindow: Code requested 16 bpc float precision, but this is unsupported. Trying to use 15 bit snorm precision instead.\n");
						fboInternalFormat = GL_RGBA16_SNORM; windowRecord->depth=64; usefloatformat = 0;
						if (!(targetWindow->gfxcaps & kPsychGfxCapSNTex16)) {
							printf("PTB-ERROR:OpenOffscreenWindow: Code requested 16 bpc float precision, but this is unsupported by this graphics card.\n");
							printf("PTB-ERROR:OpenOffscreenWindow: Tried to use 16 bit snorm format instead, but failed as this is unsupported as well.\n");
						}
					}
				break;

				case 128:
					fboInternalFormat = GL_RGBA_FLOAT32_APPLE; windowRecord->depth=128; usefloatformat = 2;
				break;
				
				default:
					fboInternalFormat = GL_RGBA8; windowRecord->depth=32; usefloatformat = 0;
			}			
		}
		
        // Floating point framebuffer on OpenGL-ES requested?
        if (PsychIsGLES(targetWindow) && (usefloatformat > 0)) {
            // Yes. We only support 32 bpc float framebuffers with alpha-blending. On less supportive hardware we fail:
            if (!(targetWindow->gfxcaps & kPsychGfxCapFPTex32) || !(targetWindow->gfxcaps & kPsychGfxCapFPFBO32)) {
                PsychErrorExitMsg(PsychError_user, "Sorry, the requested offscreen window color resolution of 32 bpc floating point is not supported by your graphics card. Game over.");
            }

            // Supported. Upgrade requested format to 32 bpc float, whatever it was before:
            fboInternalFormat = GL_RGBA_FLOAT32_APPLE; windowRecord->depth=128; usefloatformat = 2;
        }

		// Do we need additional depth buffer attachments?
		needzbuffer = (PsychPrefStateGet_3DGfx()>0) ? TRUE : FALSE;
		
		// Copy in optional multiSample argument: It defaults to zero, aka multisampling disabled.
		PsychCopyInIntegerArg(6, FALSE, &multiSample);
		if (multiSample < 0) PsychErrorExitMsg(PsychError_user, "Invalid negative multiSample level provided!");

		// Multisampled anti-aliasing requested?
		if (multiSample > 0) {
			// Yep. Supported by GPU?
			if (!(targetWindow->gfxcaps & kPsychGfxCapFBOMultisample)) {
				// No. We fall back to non-multisampled mode:
				multiSample = 0;
				
				// Tell user if warnings enabled:
				if (PsychPrefStateGet_Verbosity() > 1) {
					printf("PTB-WARNING: You requested stimulus anti-aliasing via multisampling by setting the multiSample parameter of Screen('OpenOffscreenWindow', ...) to a non-zero value.\n");
					printf("PTB-WARNING: You also requested use of the imaging pipeline. Unfortunately, your combination of operating system, graphics hardware and driver does not\n");
					printf("PTB-WARNING: support simultaneous use of the imaging pipeline and multisampled anti-aliasing.\n");
					printf("PTB-WARNING: Will therefore continue without anti-aliasing...\n\n");
					printf("PTB-WARNING: A driver upgrade may resolve this issue. Users of MacOS-X need at least OS/X 10.5.2 Leopard for support on recent ATI hardware.\n\n");
				}
			}
		}

		// Allocate framebuffer object for this Offscreen window:
		if (!PsychCreateFBO(&(windowRecord->fboTable[0]), fboInternalFormat, needzbuffer, (int) PsychGetWidthFromRect(rect), (int) PsychGetHeightFromRect(rect), multiSample, specialFlags)) {
			// Failed!
			PsychErrorExitMsg(PsychError_user, "Creation of Offscreen window in imagingmode failed for some reason :(");
		}

		// Assign this FBO as drawBuffer for mono channel of our Offscreen window:
		windowRecord->drawBufferFBO[0] = 0;
		windowRecord->fboCount = 1;
		
		// Assign it as texture as well:
		windowRecord->textureNumber = windowRecord->fboTable[0]->coltexid;
		windowRecord->textureMemorySizeBytes = 0;
		windowRecord->textureMemory = NULL;
		windowRecord->texturetarget = (specialFlags & 0x1) ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE_EXT;
		windowRecord->surfaceSizeBytes = (size_t) (PsychGetWidthFromRect(rect) * PsychGetHeightFromRect(rect) * (windowRecord->depth / 8));

		// Set bpc for FBO backed offscreen window:
		windowRecord->bpc = (int) (windowRecord->depth / 4);

		// Initial setup done, continues below after some shared code...
	}
	else {
		// Traditional texture creation code:
		
		// Special case for alpha-channel: DBL_MAX signals maximum alpha
		// value requested. In our own code we need to manually map this to
		// the maximum uint8 alpha value of 255:
		if (color.value.rgba.a == DBL_MAX) color.value.rgba.a = 255;
		
		// Allocate the texture memory:
		// We only allocate the amount really needed for given format, aka numMatrixPlanes - Bytes per pixel.
		xSize = (size_t) PsychGetWidthFromRect(rect);
		ySize = (size_t) PsychGetHeightFromRect(rect);
		windowRecord->textureMemorySizeBytes = ((size_t) (depth/8)) * xSize * ySize;
		windowRecord->textureMemory = malloc(windowRecord->textureMemorySizeBytes);
		texturePointer=(char*) windowRecord->textureMemory;
		// printf("depth=%i xsize=%i ysize=%i mem=%i ptr=%p", depth, xSize, ySize, windowRecord->textureMemorySizeBytes, texturePointer);
		// Fill with requested background color:
		nbytes=0;
		switch (depth) {
			case 8: // Pure LUMINANCE texture:
				memset((void*) texturePointer, (int) color.value.rgba.r, windowRecord->textureMemorySizeBytes);
				break;
				
			case 16: // LUMINANCE + ALPHA
				while (nbytes < windowRecord->textureMemorySizeBytes) {
					*(texturePointer++) = (psych_uint8) color.value.rgba.r;
					*(texturePointer++) = (psych_uint8) color.value.rgba.a;
					nbytes+=2;
				}
				break;
				
			case 24: // RGB:
				while (nbytes < windowRecord->textureMemorySizeBytes) {
					*(texturePointer++) = (psych_uint8) color.value.rgba.r;
					*(texturePointer++) = (psych_uint8) color.value.rgba.g;
					*(texturePointer++) = (psych_uint8) color.value.rgba.b;
					nbytes+=3;
				}
				break;        
				
			case 32: // RGBA
				if (bigendian) {
					// Code for big-endian machines, e.g., PowerPC:
					while (nbytes < windowRecord->textureMemorySizeBytes) {
						*(texturePointer++) = (psych_uint8) color.value.rgba.a;
						*(texturePointer++) = (psych_uint8) color.value.rgba.r;
						*(texturePointer++) = (psych_uint8) color.value.rgba.g;
						*(texturePointer++) = (psych_uint8) color.value.rgba.b;
						nbytes+=4;
					}
				}
				else {
					// Code for little-endian machines, e.g., IntelPC, IntelMAC, aka Pentium.
					while (nbytes < windowRecord->textureMemorySizeBytes) {
						*(texturePointer++) = (psych_uint8) color.value.rgba.b;
						*(texturePointer++) = (psych_uint8) color.value.rgba.g;
						*(texturePointer++) = (psych_uint8) color.value.rgba.r;
						*(texturePointer++) = (psych_uint8) color.value.rgba.a;
						nbytes+=4;
					}
				}
				break;
		}
	}
	
	// Shared setup code for FBO vs. non-FBO Offscreen windows:
	
	// Assign parent window and copy its inheritable properties:
	PsychAssignParentWindow(windowRecord, targetWindow);
	
    // Texture orientation is type 2 aka upright, non-transposed aka Offscreen window:
    windowRecord->textureOrientation = 2;
    
	if ((windowRecord->imagingMode & kPsychNeedFastBackingStore) || (windowRecord->imagingMode & kPsychNeedFastOffscreenWindows)) {
		// Last step for FBO backed Offscreen window: Clear it to its background color:
		PsychSetDrawingTarget(windowRecord);

		// Set default draw shader:
		PsychSetShader(windowRecord, -1);
	
		// Set background fill color:
		PsychSetGLColor(&color, windowRecord);

		// Setup alpha-blending:
		PsychUpdateAlphaBlendingFactorLazily(windowRecord);

		// Fullscreen fill of a non-onscreen window:
		PsychGLRect(windowRecord->rect);

		// Multisampling requested? If so, we need to enable it:
		if (multiSample > 0) {
			glEnable(GL_MULTISAMPLE);
			while (glGetError() != GL_NO_ERROR);
		}
		
		// Ready. Unbind it.
		PsychSetDrawingTarget(NULL);		
	}
	else {
		// Old-style setup for non-FBO Offscreen windows:
        
        // Special texture format?
		if (specialFlags & 0x1) windowRecord->texturetarget = GL_TEXTURE_2D;
        
		// Let's create and bind a new texture object and fill it with our new texture data.
		PsychCreateTexture(windowRecord);
    }

	// Assign GLSL filter-/lookup-shaders if needed:
	PsychAssignHighPrecisionTextureShaders(windowRecord, targetWindow, usefloatformat, (specialFlags & 2) ? 1 : 0);
	
    // specialFlags setting 8? Disable auto-mipmap generation:
    if (specialFlags & 0x8) windowRecord->specialflags |= kPsychDontAutoGenMipMaps;    

    // A specialFlags setting of 32? Protect texture against deletion via Screen('Close') without providing a explicit handle:
    if (specialFlags & 32) windowRecord->specialflags |= kPsychDontDeleteOnClose;    

    // Window ready. Mark it valid and return handle to userspace:
    PsychSetWindowRecordValid(windowRecord);
    
    //Return the window index and the rect argument.
    PsychCopyOutDoubleArg(1, FALSE, windowRecord->windowIndex);
    PsychCopyOutRectArg(2, FALSE, rect);

    // Ready.
    return(PsychError_none);
}
PsychError SCREENOpenWindow(void) 

{
    int						screenNumber, numWindowBuffers, stereomode, multiSample, imagingmode, specialflags;
    PsychRectType 			rect, screenrect;
    PsychColorType			color;
    psych_bool				isArgThere, didWindowOpen, useAGL;
    PsychScreenSettingsType	screenSettings;
    PsychWindowRecordType	*windowRecord;
    PsychDepthType			specifiedDepth, possibleDepths, currentDepth, useDepth;
	int                     dummy1;
	double                  dummy2, dummy3, dummy4;

	psych_bool EmulateOldPTB = PsychPrefStateGet_EmulateOldPTB();

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

    //cap the number of inputs
    PsychErrorExit(PsychCapNumInputArgs(9));   //The maximum number of inputs
    PsychErrorExit(PsychCapNumOutputArgs(2));  //The maximum number of outputs

    //get the screen number from the windowPtrOrScreenNumber.  This also checks to make sure that the specified screen exists.  
    PsychCopyInScreenNumberArg(kPsychUseDefaultArgPosition, TRUE, &screenNumber);
    if(screenNumber==-1)
        PsychErrorExitMsg(PsychError_user, "The specified onscreen window has no ancestral screen."); 

    /*
      The depth checking is ugly because of this stupid depth structure stuff.  
      Instead get a descriptor of the current video settings, change the depth field,
      and pass it to a validate function wich searches a list of valid video modes for the display.
      There seems to be no point in checking the depths alone because the legality of a particular
      depth depends on the other settings specified below.  Its probably best to wait until we have
      digested all settings and then test the full mode, declarin an invalid
      mode and not an invalid pixel size.  We could notice when the depth alone is specified 
      and in that case issue an invalid depth value.
     */  

    //find the PixelSize first because the color specifier depends on the screen depth.  
    PsychInitDepthStruct(&currentDepth);  //get the current depth
    PsychGetScreenDepth(screenNumber, &currentDepth);
    PsychInitDepthStruct(&possibleDepths); //get the possible depths
    PsychGetScreenDepths(screenNumber, &possibleDepths);

    #if PSYCH_SYSTEM == PSYCH_OSX || PSYCH_SYSTEM == PSYCH_WINDOWS
       // MK Experimental Hack: Add the special depth values 64 and 128 to the depth struct. This should 
       // allows for 16 bpc, 32 bpc floating point color buffers on the latest ATI and NVidia hardware.
	   // "Should" means: It doesn't really work with any current driver, but we leave the testcode in
	   // in the hope for future OS and driver releases ;-)
       // Unfortunately at this point of the init sequence, we are not able
       // to check if these formats are supported by the hardware. Ugly ugly ugly...
       PsychAddValueToDepthStruct(64, &possibleDepths);
       PsychAddValueToDepthStruct(128, &possibleDepths);
    #endif

//    #if PSYCH_SYSTEM == PSYCH_OSX || PSYCH_SYSTEM == PSYCH_LINUX
		// On MacOS/X and Linux with ATI Radeon X1000/HD2000/HD3000 hardware and the special
		// kernel support driver installed, we should be able to configure the hardwares
		// framebuffers into ABGR2101010 mode, ie. 2 bits alpha, 10 bpc for red, green, blue.
		// This needs support from the imaging pipeline, or manually converted stimuli, as
		// the GPU doesn't format pixel data properly, only the CRTC scans out in that format.
		// Anyway, allow this setting on OS/X and Linux:
		
		// Update: Some FireGL cards (2008 and later) claim to support this on MS-Windows. Enable
		// this option on Windows as well, so it is at least testable:
		PsychAddValueToDepthStruct(30, &possibleDepths);
//    #endif


    PsychInitDepthStruct(&specifiedDepth); //get the requested depth and validate it.  
    isArgThere = PsychCopyInSingleDepthArg(4, FALSE, &specifiedDepth);

    PsychInitDepthStruct(&useDepth);
    if(isArgThere){ //if the argument is there check that the screen supports it...
        if(!PsychIsMemberDepthStruct(&specifiedDepth, &possibleDepths))
            PsychErrorExit(PsychError_invalidDepthArg);
        else
            PsychCopyDepthStruct(&useDepth, &specifiedDepth);
    }else //otherwise use the default
        PsychCopyDepthStruct(&useDepth, &currentDepth);

    // Initialize the rect argument to the screen rectangle:
    PsychGetGlobalScreenRect(screenNumber, rect); 	//get the rect describing the screen bounds.  This is the default Rect.  

    // Override it with a user supplied rect, if one was supplied:
    isArgThere=PsychCopyInRectArg(kPsychUseDefaultArgPosition, FALSE, rect );
    if (IsPsychRectEmpty(rect)) PsychErrorExitMsg(PsychError_user, "OpenWindow called with invalid (empty) rect argument.");

	if (PSYCH_SYSTEM == PSYCH_OSX) {
		// OS/X system: Need to decide if we use a Carbon window + AGL
		// or a fullscreen context with CGL:
		
		// Default to AGL, switch to CGL if below constraints are met:
		useAGL = TRUE;
	
		// Window rect provided which has a different size than screen?

		// We do not use windowed mode if the provided window rectangle either
		// matches the target screens rectangle (and therefore its exact size)
		// or its screens global rectangle.
		PsychGetScreenRect(screenNumber, screenrect);
		if (PsychMatchRect(screenrect, rect)) useAGL=FALSE;
		PsychGetGlobalScreenRect(screenNumber, screenrect);
		if (PsychMatchRect(screenrect, rect)) useAGL=FALSE;

		// Override for use on f$%#$Fd OS/X 10.5.3 - 10.5.6 with NVidia GF 8800 GPU's:
		if (PsychPrefStateGet_ConserveVRAM() & kPsychUseAGLCompositorForFullscreenWindows) useAGL = TRUE;
	}
	else {
		// Non OS/X system: Do not use AGL ;-)
		useAGL = FALSE;
	}
	
    //find the number of specified buffers. 

    //OS X:	The number of backbuffers is not a property of the display mode but an attribute of the pixel format.
    //		Therefore the value is held by a window record and not a screen record.    

    numWindowBuffers=2;	
    PsychCopyInIntegerArg(5,FALSE,&numWindowBuffers);
    if(numWindowBuffers < 1 || numWindowBuffers > kPsychMaxNumberWindowBuffers) PsychErrorExit(PsychError_invalidNumberBuffersArg);

    stereomode=0;
    PsychCopyInIntegerArg(6,FALSE,&stereomode);
    if(stereomode < 0 || stereomode > 11) PsychErrorExitMsg(PsychError_user, "Invalid stereomode provided (Valid between 0 and 11).");
	if (stereomode!=0 && EmulateOldPTB) PsychErrorExitMsg(PsychError_user, "Sorry, stereo display functions are not supported in OS-9 PTB emulation mode.");

    multiSample=0;
    PsychCopyInIntegerArg(7,FALSE,&multiSample);
    if(multiSample < 0) PsychErrorExitMsg(PsychError_user, "Invalid multisample value provided (Valid are positive numbers >= 0).");
	if (multiSample!=0 && EmulateOldPTB) PsychErrorExitMsg(PsychError_user, "Sorry, anti-aliasing functions are not supported in OS-9 PTB emulation mode.");

	imagingmode=0;
    PsychCopyInIntegerArg(8,FALSE,&imagingmode);
    if(imagingmode < 0) PsychErrorExitMsg(PsychError_user, "Invalid imaging mode provided (See 'help PsychImagingMode' for usage info).");
	if (imagingmode!=0 && EmulateOldPTB) PsychErrorExitMsg(PsychError_user, "Sorry, imaging pipeline functions are not supported in OS-9 PTB emulation mode.");
	
	specialflags=0;
    PsychCopyInIntegerArg(9,FALSE,&specialflags);
    if (specialflags < 0 || (specialflags > 0 && specialflags!=kPsychGUIWindow)) PsychErrorExitMsg(PsychError_user, "Invalid 'specialflags' provided.");

	// We require use of the imaging pipeline if stereomode for dualwindow display is requested.
	// This makes heavy use of FBO's and blit operations, so imaging pipeline is needed.
	if ((stereomode==kPsychDualWindowStereo) || (imagingmode & kPsychNeedDualWindowOutput)) {
		// Dual window stereo requested, but imaging pipeline not enabled. Enable it:
		imagingmode|= kPsychNeedFastBackingStore;
		if (PsychPrefStateGet_Verbosity()>3) printf("PTB-INFO: Trying to enable imaging pipeline for dual-window stereo display mode or dual-window output mode...\n");
	}
	
    //set the video mode to change the pixel size.  TO DO: Set the rect and the default color  
    PsychGetScreenSettings(screenNumber, &screenSettings);    
    PsychInitDepthStruct(&(screenSettings.depth));
    PsychCopyDepthStruct(&(screenSettings.depth), &useDepth);

    // Here is where all the work goes on:

    // If the screen is not already captured then to that:
    if(!PsychIsScreenCaptured(screenNumber) && !useAGL) {
        PsychCaptureScreen(screenNumber);
    }

#if PSYCH_SYSTEM == PSYCH_WINDOWS
    // On M$-Windows we currently only support - and therefore require >= 30 bpp color depth.
    if (PsychGetScreenDepthValue(screenNumber) < 30) {
		// Display running at less than 30 bpp. OpenWindow will fail on M$-Windows anyway, so let's abort
		// now.

		// Output warning text:
        printf("PTB-ERROR: Your display screen %i is not running at the required color depth of at least 30 bit.\n", screenNumber);
        printf("PTB-ERROR: The current setting is %i bit color depth..\n", PsychGetScreenDepthValue(screenNumber));
        printf("PTB-ERROR: This will not work on Microsoft Windows operating systems.\n");
        printf("PTB-ERROR: Please use the 'Display settings' control panel of Windows to change the color depth to\n");
        printf("PTB-ERROR: 32 bits per pixel ('True color' or 'Highest' setting) and then retry. It may be neccessary\n");
        printf("PTB-ERROR: to restart Matlab after applying the change...\n");
        fflush(NULL);

		// Release the captured screen:
		PsychRestoreScreenSettings(screenNumber);
		PsychReleaseScreen(screenNumber);

        // Reset master assignment to prepare possible further dual-window config operations:
		sharedContextWindow = NULL;

		// Abort with Matlab error:
		PsychErrorExitMsg(PsychError_user, "Insufficient color depth setting for display device (smaller than 30 bpp).");
    }

#endif

    //if (PSYCH_DEBUG == PSYCH_ON) printf("Entering PsychOpenOnscreenWindow\n");
    PsychCopyDepthStruct(&(screenSettings.depth), &useDepth);
	
	// Create the onscreen window and perform initialization of everything except
	// imaging pipeline and a few other special quirks. If sharedContextWindow is non-NULL,
	// the new window will share its OpenGL context ressources with sharedContextWindow.
	// This is typically used for dual-window stereo mode. Btw. If imaging pipeline is really
	// active, we force multiSample to zero: This way the system backbuffer / pixelformat
	// is enabled without multisampling support, as we do all the multisampling stuff ourselves
	// within the imaging pipeline with multisampled drawbuffer FBO's...
    didWindowOpen=PsychOpenOnscreenWindow(&screenSettings, &windowRecord, numWindowBuffers, stereomode, rect, ((imagingmode==0 || imagingmode==kPsychNeedFastOffscreenWindows) ? multiSample : 0), sharedContextWindow, specialflags);
    if (!didWindowOpen) {
        if (!useAGL) {
			PsychRestoreScreenSettings(screenNumber);
			PsychReleaseScreen(screenNumber);
		}

		// Reset master assignment to prepare possible further dual-window config operations:
		sharedContextWindow = NULL;

        // We use this dirty hack to exit with an error, but without printing
        // an error message. The specific error message has been printed in
        // PsychOpenOnscreenWindow() already..
        PsychErrMsgTxt("");
    }

    // Sufficient display depth for full alpha-blending and such?
    if (PsychGetScreenDepthValue(screenNumber) < 24) {
        // Nope. Output a little warning.
        printf("PTB-WARNING: Your display screen %i is not running at 24 bit color depth or higher.\n", screenNumber);
        printf("PTB-WARNING: The current setting is %i bit color depth..\n", PsychGetScreenDepthValue(screenNumber));
        printf("PTB-WARNING: This could cause failure to work correctly or visual artifacts in stimuli\n");
        printf("PTB-WARNING: that involve Alpha-Blending. It can also cause drastically reduced color resolution\n");
        printf("PTB-WARNING: for your stimuli! Please try to switch your display to 'True Color' (Windows)\n");
        printf("PTB-WARNING: our 'Millions of Colors' (MacOS-X) to get rid of this warning and the visual artifacts.\n");
        fflush(NULL);
    }
    
	// Define clear color: This depends on the color range of our onscreen window...
    isArgThere=PsychCopyInColorArg(kPsychUseDefaultArgPosition, FALSE, &color); //get from user
    if(!isArgThere) PsychLoadColorStruct(&color, kPsychIndexColor, PsychGetWhiteValueFromWindow(windowRecord)); //or use the default
    PsychCoerceColorMode(&color);

    // The imaging pipeline and graphics drivers had over 5 years of time to mature. As of 2012, imaging pipeline based
    // support for fast offscreen windows and for stereoscopic display modes is far superior in performance,
    // robustness, flexibility and convenience to the legacy method which was used in ptb by default so far.
    // Now it is 2012+ and we switch the defaults: If the GPU+driver combo supports it, and usercode doesn't
    // actively opt-out of it, we auto-enable use of FBO backed fast offscreen windows. We don't auto-enable
    // the full pipeline for stereoscopic display modes, but we print some recommendations to the user to
    // consider enabling the full pipeline for stereo display:
    if ((windowRecord->gfxcaps & kPsychGfxCapFBO) && !(PsychPrefStateGet_ConserveVRAM() & kPsychDontAutoEnableImagingPipeline)) {
        // Support for basic use of the PTB imaging pipeline and/or for fast offscreen windows
        // is available - a GPU + driver combo with support for OpenGL framebuffer objects with
        // at least RGBA8 format and rectangle rendertargets.
        // Usercode doesn't disallow automatic use of imaging pipeline or fast offscreen windows,
        // ie. it didn't set the kPsychDontAutoEnableImagingPipeline conserveVRAM flag.
        // Good!
        
        // We will therefore auto-enable use of fast offscreen windows:
        imagingmode |= kPsychNeedFastOffscreenWindows;
        
        // Is a stereomode requested which would benefit from enabling the full imaging pipeline?
        if (stereomode > 0) {
	    if (((stereomode == kPsychOpenGLStereo) && !(windowRecord->gfxcaps & kPsychGfxCapNativeStereo)) || (stereomode == kPsychFrameSequentialStereo)) {
		// Native OpenGL quad-buffered frame-sequential stereo requested, but unsupported by gpu & driver.
		// Or use of our own method requested. We have FBO and framebuffer blit support, so we can roll our
		// own framesequential stereo by use of the imaging pipeline. Enable basic imaging pipeline:
		imagingmode |= kPsychNeedFastBackingStore;

		// Override stereomode to our own homegrown implementation:
		stereomode = kPsychFrameSequentialStereo;
		windowRecord->stereomode = stereomode;

		if (PsychPrefStateGet_Verbosity() > 2) {
		    printf("\n");
		    printf("PTB-INFO: Your script requests use of frame-sequential stereo, but your graphics card\n");
		    printf("PTB-INFO: and driver doesn't support this. I will now fully enable the imaging pipeline\n");
		    printf("PTB-INFO: and use my own home-grown frame-sequential stereo implementation. Note that this\n");
		    printf("PTB-INFO: may not be as robust and high-performance as using a graphics card with native\n");
		    printf("PTB-INFO: frame-sequential stereo support. But let's see what i can do for you...\n\n");
		}
	    }
	    else {
		// Yes: Provide the user with recommendations to enable the pipeline.
		if (!(imagingmode & kPsychNeedFastBackingStore) && (PsychPrefStateGet_Verbosity() > 2)) {
		    printf("\n");
		    printf("PTB-INFO: Your script requests use of a stereoscopic display mode (stereomode = %i).\n", stereomode);
		    printf("PTB-INFO: Stereoscopic stimulus display is usually more flexible, convenient and robust if\n");
		    printf("PTB-INFO: the Psychtoolbox imaging pipeline is enabled. Your graphics card is capable\n");
		    printf("PTB-INFO: of using the pipeline but your script doesn't enable use of the pipeline.\n");
		    printf("PTB-INFO: I recommend you enable use of the pipeline for enhanced stereo stimulus display.\n");
		    printf("PTB-INFO: Have a look at the demoscript ImagingStereoDemo.m on how to do this.\n\n");
		}
	    }
        }
    }

	// Query if OpenGL stereo is natively supported or if our own emulation mode will work:
	if ((((stereomode == kPsychOpenGLStereo) && !(windowRecord->gfxcaps & kPsychGfxCapNativeStereo)) || (stereomode == kPsychFrameSequentialStereo)) &&
	    (!(imagingmode & kPsychNeedFastBackingStore) || (windowRecord->stereomode != kPsychFrameSequentialStereo) || !(windowRecord->gfxcaps & kPsychGfxCapFBO))) {
		// OpenGL native stereo was requested, but is obviously not supported and we can't roll our own implementation either :-(
		printf("\nPTB-ERROR: Asked for OpenGL native stereo (frame-sequential mode) but this doesn't seem to be supported by your graphics hardware or driver.\n");
		printf("PTB-ERROR: Unfortunately using my own implementation via imaging pipeline did not work either, due to lack of hardware support, or because\n");
		printf("PTB-ERROR: did not allow me to auto-enable the pipeline and use this method. This means game over!\n");
		if (PSYCH_SYSTEM == PSYCH_OSX) {
			printf("PTB-ERROR: Frame-sequential stereo should be supported on all recent ATI/AMD and NVidia cards on OS/X, except for the Intel onboard chips,\n");
			printf("PTB-ERROR: at least in fullscreen mode with OS/X 10.5, and also mostly on OS/X 10.4. If it doesn't work, check for OS updates etc.\n\n");
		}
		else {
			printf("PTB-ERROR: Frame-sequential native stereo on Windows or Linux is usually only supported with the professional line of graphics cards\n");
			printf("PTB-ERROR: from NVidia and ATI/AMD, e.g., NVidia Quadro series or ATI Fire series. If you happen to have such a card, check\n");
			printf("PTB-ERROR: your driver settings and/or update your graphics driver.\n\n");
		}
		PsychErrMsgTxt("Frame-Sequential stereo display mode requested, but unsupported. Emulation unsupported as well. Game over!");
	}

	// Special setup code for dual window stereomode or output mode:
	if (stereomode == kPsychDualWindowStereo || (imagingmode & kPsychNeedDualWindowOutput)) {
		if (sharedContextWindow) {
			// This is creation & setup of the slave onscreen window, ie. the one
			// representing the right-eye or channel 1 view. This window doesn't do much. It
			// is not used or referenced in the users experiment script. It receives
			// its final image content during Screen('Flip') operation of the master
			// onscreen window, then gets flipped in sync with the master window.
			
			// Ok, we already have the slave window open and it shares its OpenGL context
			// with the master window. Reset its internal reference to the master:
			windowRecord->slaveWindow = NULL;
			
			// Reset imagingmode for this window prior to imaging pipeline setup. This
			// window is totally passive so it doesn't need the imaging pipeline.
			imagingmode = 0;

			// Assign this window to the master window as a slave:
			sharedContextWindow->slaveWindow = windowRecord;
			
			// Try to optionally enable framelock / swaplock extensions for the window-pair
			// if this is supported by the given system configuration. If supported, this
			// should guarantee perfect synchronization of bufferswaps across the window-pair:
			PsychOSSetupFrameLock(sharedContextWindow, windowRecord);

			// Reset master assignment to prepare possible further dual-window config operations:
			sharedContextWindow = NULL;

			// Activate the IdentitiyBlitChain for the slave window and add a single identity blit
			// operation to it: This is needed in PsychPreFlipOperations() for final copy of stimulus
			// image into this slave window:
			PsychPipelineAddBuiltinFunctionToHook(windowRecord, "IdentityBlitChain", "Builtin:IdentityBlit", INT_MAX, "");
			PsychPipelineEnableHook(windowRecord, "IdentityBlitChain");

			if (PsychPrefStateGet_Verbosity()>3) printf("PTB-INFO: Created master-slave window relationship for dual-window stereo/output display mode...\n");

			// Special config finished. The master-slave combo should work from now on...			
		}
		else {
			// This is initial setup & creation of the master onscreen window, ie. the one
			// representing the left-eye or channel 0 view and doing all the heavy work, acting as a
			// proxy for both windows.
			
			// Not much to do here. Just store its windowRecord as a reference for creation
			// of the slave window. We'll need it for that purpose...
			sharedContextWindow = windowRecord;
		}
	}

	// Set special half-width flag for window if we are either in a dual-display/dual-view stereo mode or if
	// if is requested as part of the imagingMode flag. This will cause PTB 2D drawing routines and window size
	// query routines etc. to return an effective window width or window rect only half the real width.
	if (windowRecord->stereomode==kPsychFreeFusionStereo || windowRecord->stereomode==kPsychFreeCrossFusionStereo || (imagingmode & kPsychHalfWidthWindow)) {
		windowRecord->specialflags = windowRecord->specialflags | kPsychHalfWidthWindow;
		imagingmode = imagingmode & (~kPsychHalfWidthWindow);
	}

    // Similar handling for twice-width windows: Used for certain packed-pixels (2 stimulus pixels in one fb pixel) formats:
	if (imagingmode & kPsychTwiceWidthWindow) {
		windowRecord->specialflags = windowRecord->specialflags | kPsychTwiceWidthWindow;
		imagingmode = imagingmode & (~kPsychTwiceWidthWindow);
	}

	// Similar handling for windows of half the real height, except that none of our built-in stereo modes requires these,
	// so this is only done on request from external code via the imagingmode flag kPsychHalfHeightWindow.
	// One use of this is when using interleaved line stereo mode (PsychImaging(...'InterleavedLineStereo')) where windows
	// only have a useable net height of half their physical height:
	if (imagingmode & kPsychHalfHeightWindow) {
		windowRecord->specialflags = windowRecord->specialflags | kPsychHalfHeightWindow;
		imagingmode = imagingmode & (~kPsychHalfHeightWindow);
	}

	// Define windows clientrect. It is a copy of windows rect, but stretched or compressed
    // to twice or half the width or height of the windows rect, depending on the special size
    // flags. clientrect is used as reference for all size query functions Screen('Rect'), Screen('WindowSize')
    // and for all Screen 2D drawing functions:
    PsychSetupClientRect(windowRecord);

	// Initialize internal image processing pipeline if requested:
	if (numWindowBuffers > 0) PsychInitializeImagingPipeline(windowRecord, imagingmode, multiSample);
	
	// On OS-X, if we are in quad-buffered frame sequential stereo mode, we automatically generate
	// blue-line-sync style sync lines for use with stereo shutter glasses. We don't do this
	// by default on Windows or Linux: These systems either don't have stereo capable hardware,
	// or they have some and its drivers already take care of sync signal generation.
	if (((PSYCH_SYSTEM == PSYCH_OSX) && (windowRecord->stereomode == kPsychOpenGLStereo)) || (windowRecord->stereomode == kPsychFrameSequentialStereo)) {
		if (PsychPrefStateGet_Verbosity()>3) printf("PTB-INFO: Enabling internal blue line sync renderer for quad-buffered stereo...\n");
		PsychPipelineAddBuiltinFunctionToHook(windowRecord, "LeftFinalizerBlitChain", "Builtin:RenderStereoSyncLine", INT_MAX, "");
		PsychPipelineEnableHook(windowRecord, "LeftFinalizerBlitChain");		
		PsychPipelineAddBuiltinFunctionToHook(windowRecord, "RightFinalizerBlitChain", "Builtin:RenderStereoSyncLine", INT_MAX, "");
		PsychPipelineEnableHook(windowRecord, "RightFinalizerBlitChain");		
	}

	// Activate new onscreen window for userspace drawing: If imaging pipeline is active, this
	// will bind the correct rendertargets for the first time. We soft-reset first to get
	// into a defined state:
	PsychSetDrawingTarget((PsychWindowRecordType*) 0x1);
	PsychSetDrawingTarget(windowRecord);

    // Set the clear color and perform a backbuffer-clear:
    PsychConvertColorToDoubleVector(&color, windowRecord, windowRecord->clearColor);
    PsychGLClear(windowRecord);

    // Mark end of drawing op. This is needed for single buffered drawing:
    PsychFlushGL(windowRecord);

    // Make sure no OpenGL errors happened up to this point:
    PsychTestForGLErrors();

    // If we are in logo-startup mode (former blue-screen mode) and double-buffering
    // is enabled, then do an initial bufferswap & clear, so the display starts in
    // the user selected background color instead of staying at the blue screen or
    // logo display until the Matlab script first calls 'Flip'.
    if (((PsychPrefStateGet_VisualDebugLevel()>=4) || (windowRecord->stereomode > 0)) && numWindowBuffers>=2) {
      // Do three immediate bufferswaps by an internal call to Screen('Flip'). This will also
      // take care of clearing the backbuffer in preparation of first userspace drawing
      // commands and such. We need up-to 3 calls to clear triple-buffered setups from framebuffer junk.
      PsychFlipWindowBuffers(windowRecord, 0, 0, 0, 0, &dummy1, &dummy2, &dummy3, &dummy4);
      PsychFlipWindowBuffers(windowRecord, 0, 0, 0, 0, &dummy1, &dummy2, &dummy3, &dummy4);
      PsychFlipWindowBuffers(windowRecord, 0, 0, 0, 0, &dummy1, &dummy2, &dummy3, &dummy4);
      // Display now shows background color, so user knows that PTB's 'OpenWindow'
      // procedure is successfully finished.
    }

    PsychTestForGLErrors();

    // Reset flipcounter to zero:
    windowRecord->flipCount = 0;
	
    //Return the window index and the rect argument.
    PsychCopyOutDoubleArg(1, FALSE, windowRecord->windowIndex);

    // Optionally return the windows clientrect:
    PsychCopyOutRectArg(2, FALSE, windowRecord->clientrect);

    return(PsychError_none);   
}
PsychError SCREENDrawTexture(void) 
{
static char synopsisString[] = 
	"Draw the texture specified via 'texturePointer' into the target window specified via 'windowPointer'. "
	"In the the OS X Psychtoolbox textures replace offscreen windows for fast drawing of images during animation."
	"'sourceRect' specifies a rectangular subpart of the texture to be drawn (Defaults to full texture). "
	"'destinationRect' defines the rectangular subpart of the window where the texture should be drawn. This defaults"
	"to centered on the screen. "
	"'rotationAngle' Specifies a rotation angle in degree for rotated drawing of the texture (Defaults to 0 deg. = upright). "
	"'filterMode' How to compute the pixel color values when the texture is drawn magnified, minified or drawn shifted, e.g., "
	"if sourceRect and destinationRect do not have the same size or if sourceRect specifies fractional pixel values. 0 = Nearest "
	"neighbour filtering, 1 = Bilinear filtering - this is the default. 'globalAlpha' A global alpha transparency value to apply "
	"to the whole texture for blending. Range is 0 = fully transparent to 1 = fully opaque, defaults to one. If both, an alpha-channel "
	"and globalAlpha are provided, then the final alpha is the product of both values. 'modulateColor', if provided, overrides the "
	"'globalAlpha' value. If 'modulateColor' is specified, the 'globalAlpha' value will be ignored. 'modulateColor' will be a global "
	"color that gets applied to the texture as a whole, i.e., it modulates each color channel. E.g., modulateColor = [128 255 0] would "
	"leave the green- and alpha-channel untouched, but it would multiply the blue channel with 0 - set it to zero blue intensity, and "
	"it would multiply each texel in the red channel by 128/255 - reduce its intensity to 50%. The most interesting application of "
	"'modulateColor' is drawing of arbitrary complex shapes of selectable color: Simply generate an all-white luminance texture of "
	"arbitrary shape, possibly with alpha channel, then draw it with 'modulateColor' set to the wanted color and global alpha value.\n"
	"'textureShader' (optional): If you provide a valid handle of a GLSL shader, this shader will be applied to the texture during "
	"drawing. If the texture already has a shader assigned (via Screen('MakeTexture') or automatically by PTB for some reason), then "
	"the shader provided here as 'textureShader' will silently override the shader assigned earlier. Application of shaders this way "
	"is mostly useful for application of simple single-pass image processing operations to a texture, e.g., a simple blur or a "
	"deinterlacing operation for a video texture. If you intend to use this texture multiple times or if you need more complex image "
	"processing, e.g., multi-pass operations, better use the Screen('TransformTexture') command. It allows for complex operations to "
	"be applied and is more flexible.\n"
	"'specialFlags' optional argument: Allows to pass a couple of special flags to influence the drawing. The flags can be combined "
	"by mor() ing them together. A value of kPsychUseTextureMatrixForRotation will use a different mode of operation for drawing of "
	"rotated textures, where the drawn 'dstRect' texture rectangle is always upright, but texels are retrieved at rotated positions, "
	"as if the 'srcRect' rectangle would be rotated. If you set a value of kPsychDontDoRotation then the rotation angle will not be "
	"used to rotate the texture. Instead it will be passed to a bount texture shader (if any), which is free to interpret the "
	"'rotationAngle' parameters is it wants - e.g., to implement custom texture rotation."
	"\n\n"
	"'auxParameters' optional argument: If this is set as a vector with at least 4 components, and a multiple of four components, "
	"then these values are passed to a shader (if any is bound) as 'auxParameter0....n'. The current implementation supports at "
	"most 32 values per draw call. This is mostly useful when drawing procedural textures if one needs to pass more additional "
	"parameters to define the texture than can fit into other parameter fields. See 'help ProceduralShadingAPI' for more info. "
	"\n\n"
	"If you want to draw many textures to the same onscreen- or offscreen window, use the function Screen('DrawTextures'). "
	"It accepts the same arguments as this function, but is optimized to draw many textures in one call.";
	
	// If you change useString then also change the corresponding synopsis string in ScreenSynopsis.c
	static char useString[] = "Screen('DrawTexture', windowPointer, texturePointer [,sourceRect] [,destinationRect] [,rotationAngle] [, filterMode] [, globalAlpha] [, modulateColor] [, textureShader] [, specialFlags] [, auxParameters]);";
	//                                               1              2                3             4                5                6              7				8					9				10				 11

	PsychWindowRecordType		*source, *target;
	PsychRectType			sourceRect, targetRect, tempRect;
	double rotationAngle = 0;   // Default rotation angle is zero deg. = upright.
	int filterMode = 1;         // Default filter mode is bilinear filtering.
	double globalAlpha = 1.0;   // Default global alpha is 1 == no effect.
	PsychColorType	color;
	int textureShader, backupShader;
	double*							auxParameters;
	int								numAuxParams, numAuxComponents, m, n, p;
	int specialFlags = 0;

    //all subfunctions should have these two lines.  
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    //Get the window structure for the onscreen window.  It holds the onscreein GL context which we will need in the
    //final step when we copy the texture from system RAM onto the screen.
    PsychErrorExit(PsychCapNumInputArgs(11));   	
    PsychErrorExit(PsychRequireNumInputArgs(2)); 	
    PsychErrorExit(PsychCapNumOutputArgs(0)); 
	
    //Read in arguments
    PsychAllocInWindowRecordArg(1, kPsychArgRequired, &target);
    PsychAllocInWindowRecordArg(2, kPsychArgRequired, &source);
    if(source->windowType!=kPsychTexture) {
      PsychErrorExitMsg(PsychError_user, "The first argument supplied was a window pointer, not a texture pointer");
    }

    PsychCopyRect(sourceRect,source->clientrect);
    PsychCopyInRectArg(3, kPsychArgOptional, sourceRect);
    if (IsPsychRectEmpty(sourceRect)) return(PsychError_none);

    PsychCopyRect(tempRect, target->clientrect);    
    PsychCenterRectInRect(sourceRect, tempRect, targetRect);
    PsychCopyInRectArg(4, kPsychArgOptional, targetRect);
    if (IsPsychRectEmpty(targetRect)) return(PsychError_none);

    PsychCopyInDoubleArg(5, kPsychArgOptional, &rotationAngle);
    PsychCopyInIntegerArg(6, kPsychArgOptional, &filterMode);
    if (filterMode<0 || filterMode>3) {
        PsychErrorExitMsg(PsychError_user, "filterMode needs to be 0 for nearest neighbour filter, or 1 for bilinear filter, or 2 for mipmapped filter or 3 for mipmapped-linear filter.");    
    }

	// Copy in optional 'globalAlpha': We don't put restrictions on its valid range
	// anymore - That made sense for pure fixed function LDR rendering, but no longer
	// for HDR rendering or procedural shading.
    PsychCopyInDoubleArg(7, kPsychArgOptional, &globalAlpha);
    
    PsychSetDrawingTarget(target);
    PsychUpdateAlphaBlendingFactorLazily(target);
	
	if(PsychCopyInColorArg(8, kPsychArgOptional, &color)) {
		// set globalAlpha to DBL_MAX to signal that PsychBlitTexture() shouldn't
		// use this parameter and not set any modulate color, cause we do it.
		globalAlpha = DBL_MAX;
		
		// Setup global vertex color as modulate color for texture drawing:
		PsychCoerceColorMode(&color);
		// This call stores unclamped color in target->currentColor, as needed
		// if color is to be processed by some bound shader (procedural or filtershader)
		// inside PsychBlitTextureToDisplay():
		PsychConvertColorToDoubleVector(&color, target, (GLdouble*) &(target->currentColor));
		// Submit the same color to fixed function pipe attribute as well, in case no
		// shader is bound, or shader pulls from standard color attribute (we can't know yet):
		glColor4dv(target->currentColor);
	}

	// Assign optional override texture shader, if any provided:
	textureShader = -1;
    PsychCopyInIntegerArg(9, kPsychArgOptional, &textureShader);

	// Assign any other optional special flags:
    PsychCopyInIntegerArg(10, kPsychArgOptional, &specialFlags);
	
	// Set rotation mode flag for texture matrix rotation if secialFlags is set accordingly:
	if (specialFlags & kPsychUseTextureMatrixForRotation) source->specialflags|=kPsychUseTextureMatrixForRotation;
	// Set rotation mode flag for no fixed function pipeline rotation if secialFlags is set accordingly:
	if (specialFlags & kPsychDontDoRotation) source->specialflags|=kPsychDontDoRotation;

	// Optional auxParameters:
	auxParameters = NULL;
	m=n=p=0;
	if (PsychAllocInDoubleMatArg(11, kPsychArgOptional, &m, &n, &p, &auxParameters)) {
		if ((p!=1) || (m * n < 4) || (((m*n) % 4)!=0)) PsychErrorExitMsg(PsychError_user, "The 11th argument must be a vector of 'auxParameter' values with a multiple of 4 components.");
	}
	numAuxParams = m*n;
	target->auxShaderParamsCount = numAuxParams;

	// Pass auxParameters for current primitive in the auxShaderParams field.
	if (numAuxParams > 0) {
		target->auxShaderParams = auxParameters;
	}
	else {
		target->auxShaderParams = NULL;
	}
	
	if (textureShader > -1) {
		backupShader = source->textureFilterShader;
		source->textureFilterShader = -1 * textureShader;
		PsychBlitTextureToDisplay(source, target, sourceRect, targetRect, rotationAngle, filterMode, globalAlpha);	
		source->textureFilterShader = backupShader;
	}
	else {
		PsychBlitTextureToDisplay(source, target, sourceRect, targetRect, rotationAngle, filterMode, globalAlpha);	
	}
	
	// Reset rotation mode flag:
	source->specialflags &= ~(kPsychUseTextureMatrixForRotation | kPsychDontDoRotation);
	
	target->auxShaderParams = NULL;
	target->auxShaderParamsCount = 0;
	
    // Mark end of drawing op. This is needed for single buffered drawing:
    PsychFlushGL(target);

    return(PsychError_none);

}
// Batch-drawing version of DrawTexture:
PsychError SCREENDrawTextures(void) 
{
	// If you change useString then also change the corresponding synopsis string in ScreenSynopsis.c 1 2 3 4 5 6 7 8
	static char useString[] = "Screen('DrawTextures', windowPointer, texturePointer(s) [, sourceRect(s)] [, destinationRect(s)] [, rotationAngle(s)] [, filterMode(s)] [, globalAlpha(s)] [, modulateColor(s)] [, textureShader] [, specialFlags] [, auxParameters]);";
	//                                               1              2                    3                 4                      5                    6                 7				    8					9				 10					11
	
	static char synopsisString[] = "Draw many textures at once, either one texture to many locations or many textures.\n"
	"This function accepts the same parameters as Screen('DrawTexture'), but it is optimized for drawing many textures. "
	"You can leave out each argument, a default setting will be used in that case, provide it once to apply it to all "
	"drawn items, or provide a vector or matrix with a individual setting for each drawn item. If you provide multiple "
	"settings per argument, then the number must match between all arguments.\n\n"
	"Examples:\n"
	"a) One texture drawn to different locations at different orientations: Provide one texture handle for the texturePointer, "
	"a 4 row by n columns matrix for 'destinationRect' to provide target rectangles for n locations, provide a n component "
	"vector of 'rotationAngles' for the n different orientations of the n drawn texture patches.\n"
	"b) n textures drawn to n different locations: Same as a) but provide a n component vector of 'texturePointers' one for "
	"each texture to be drawn to one of n locations at n angles.\n";

	PsychWindowRecordType			*source, *target;
	PsychRectType					sourceRect, targetRect, tempRect;
	PsychColorType	color;
	GLdouble						dVals[4]; 
    double							*dstRects, *srcRects, *colors, *penSizes, *globalAlphas, *filterModes, *rotationAngles;
	unsigned char					*bytecolors;
	int								numTexs, numdstRects, numsrcRects, i, j, nc, mc, nrsize, m, n, p, numAngles, numFilterModes, numAlphas, numRef;
	double*							texids;
	double							rotationAngle, globalAlpha, filterMode;
	double*							auxParameters;
	int								numAuxParams, numAuxComponents;

	int textureShader, backupShader;
	int specialFlags = 0;

    //all subfunctions should have these two lines.  
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    //Get the window structure for the onscreen window.  It holds the onscreen GL context which we will need in the
    //final step when we copy the texture from system RAM onto the screen.
    PsychErrorExit(PsychCapNumInputArgs(11));   	
    PsychErrorExit(PsychRequireNumInputArgs(2)); 	
    PsychErrorExit(PsychCapNumOutputArgs(0)); 
	
	// The target window is a fixed parameter:
    PsychAllocInWindowRecordArg(1, kPsychArgRequired, &target);
	
	// First get all source texture handles:
	PsychAllocInDoubleMatArg(2, kPsychArgRequired, &m, &n, &p, &texids);
	if ((p!=1) || (m>1 && n!=1) || (n>1 && m!=1)) PsychErrorExitMsg(PsychError_user, "The second argument must be either a row- or columnvector of valid texture handles.");
	// This is the number of texture handles:
	numTexs = m * n;

	// Only one texture?
	if (numTexs == 1) {
		// Yes. Allocate it in the conventional way:
		PsychAllocInWindowRecordArg(2, kPsychArgRequired, &source);
		if(source->windowType!=kPsychTexture) {
			PsychErrorExitMsg(PsychError_user, "The second argument supplied was not a texture handle!");
		}
	}

	// Query, allocate and copy in all vectors...
	numdstRects = 4;
	nrsize = 0;
	colors = NULL;
	bytecolors = NULL;
	penSizes = NULL;
	
	// The negative position -4 means: dstRects coords are expected at position 4, but they are optional.
	// NULL means - don't want a size's vector.
	PsychPrepareRenderBatch(target, -4, &numdstRects, &dstRects, 8, &nc, &mc, &colors, &bytecolors, 5, &nrsize, &penSizes);

	// At this point, target is set up as target window, i.e. its GL-Context is active, it is set as drawing target,
	// alpha blending is set up according to Screen('BlendFunction'), and the drawing color is set if it is a singular one.
	if (nc <= 1) {
		// Only one - or no - color provided. One or none?
		if(PsychCopyInColorArg(8, kPsychArgOptional, &color)) {
			// One global modulate color provided:

			// Setup global vertex color as modulate color for texture drawing:
			PsychCoerceColorMode(&color);
			PsychSetGLColor(&color, target);
		}
		else {
			// No modulateColor provided: Don't use this parameter:
			nc = 0;
		}
	}

	// Try to get source rects:
	m=n=p=0;
	if (PsychAllocInDoubleMatArg(3, kPsychArgOptional, &m, &n, &p, &srcRects)) {
		if ((p!=1) || (m!=1 && m!=4)) PsychErrorExitMsg(PsychError_user, "The third argument must be either empty, or a single srcRect 4 component row vector, or a 4 row by n column matrix with srcRects for all objects to draw, not a 3D matrix!");
		// Ok, its a one row or four row matrix:
		if (m==4) {
			// Potentially multiple source rects provided:
			numsrcRects = n;
		}
		else {
			// Its a one row vector: This is either a single srcRect for all textures, or something invalid:
			if (n!=4) PsychErrorExitMsg(PsychError_user, "The third argument must be either empty, or a single srcRect 4 component row vector, or a 4 row by n column matrix with srcRects for all objects to draw!");
			// Single srcRect provided:
			numsrcRects = 1;
		}
	}
	else {
		// No srcRects provided:
		numsrcRects = 0;
	}
	
	// Optional rotation angles:
	m=n=p=0;
	if (PsychAllocInDoubleMatArg(5, kPsychArgOptional, &m, &n, &p, &rotationAngles)) {
		if ((p!=1) || (m>1 && n!=1) || (n>1 && m!=1)) PsychErrorExitMsg(PsychError_user, "The fifth argument must be either a row- or columnvector of rotation angles.");
	}
	numAngles = m * n;

	// Default to 0 degree rotation -- upright drawing:
	rotationAngle = (numAngles == 1) ? rotationAngles[0] : 0.0;
	
	// Optional filter modes:
	m=n=p=0;
	if (PsychAllocInDoubleMatArg(6, kPsychArgOptional, &m, &n, &p, &filterModes)) {
		if ((p!=1) || (m>1 && n!=1) || (n>1 && m!=1)) PsychErrorExitMsg(PsychError_user, "The sixth argument must be either a row- or columnvector of filterModes.");
	}
	numFilterModes = m * n;

	// Default to bilinear filtering:
	filterMode = (numFilterModes == 1) ? filterModes[0] : 1;
	
	// Optional globalAlphas:
	m=n=p=0;
	if (PsychAllocInDoubleMatArg(7, kPsychArgOptional, &m, &n, &p, &globalAlphas)) {
		if ((p!=1) || (m>1 && n!=1) || (n>1 && m!=1)) PsychErrorExitMsg(PsychError_user, "The seventh argument must be either a row- or columnvector of globalAlpha values.");
	}
	numAlphas = m * n;
	globalAlpha = (numAlphas == 1) ? globalAlphas[0] : 1.0;
	
	// Optional auxParameters:
	auxParameters = NULL;
	m=n=p=0;
	if (PsychAllocInDoubleMatArg(11, kPsychArgOptional, &m, &n, &p, &auxParameters)) {
		if ((p!=1) || (m < 4) || ((m % 4) !=0)|| (n < 1)) PsychErrorExitMsg(PsychError_user, "The 11th argument must be a column vector or matrix of 'auxParameter' values with at least 4 components and component count a multiple of four.");
	}
	numAuxParams = n;
	numAuxComponents = m;
	
	// Check for consistency: Each parameter must be either not present, present once,
	// or present as many times as all other multi-parameters:
	numRef = (numsrcRects > numdstRects) ? numsrcRects : numdstRects;
	numRef = (numRef > numTexs) ? numRef : numTexs;
	numRef = (numRef > nc) ? numRef : nc;
	numRef = (numRef > numAlphas) ? numRef : numAlphas;
	numRef = (numRef > numFilterModes) ? numRef : numFilterModes;
	numRef = (numRef > numAngles) ? numRef : numAngles;
	numRef = (numRef > numAuxParams) ? numRef : numAuxParams;

	if (numTexs > 1 && numTexs != numRef) {
		printf("PTB-ERROR: Number of provided texture handles %i doesn't match number of other primitives %i!\n", numTexs, numRef);
		PsychErrorExitMsg(PsychError_user, "Inconsistent number of arguments provided to Screen('DrawTextures').");
	}

	if (numsrcRects > 1 && numsrcRects != numRef) {
		printf("PTB-ERROR: Number of provided source rectangles %i doesn't match number of other primitives %i!\n", numsrcRects, numRef);
		PsychErrorExitMsg(PsychError_user, "Inconsistent number of arguments provided to Screen('DrawTextures').");
	}
	
	if (numdstRects > 1 && numdstRects != numRef) {
		printf("PTB-ERROR: Number of provided destination rectangles %i doesn't match number of other primitives %i!\n", numdstRects, numRef);
		PsychErrorExitMsg(PsychError_user, "Inconsistent number of arguments provided to Screen('DrawTextures').");
	}
		
	if (numAngles > 1 && numAngles != numRef) {
		printf("PTB-ERROR: Number of provided rotation angles %i doesn't match number of other primitives %i!\n", numAngles, numRef);
		PsychErrorExitMsg(PsychError_user, "Inconsistent number of arguments provided to Screen('DrawTextures').");
	}

	if (numAlphas > 1 && numAlphas != numRef) {
		printf("PTB-ERROR: Number of provided global alpha values %i doesn't match number of other primitives %i!\n", numAlphas, numRef);
		PsychErrorExitMsg(PsychError_user, "Inconsistent number of arguments provided to Screen('DrawTextures').");
	}

	if (numFilterModes > 1 && numFilterModes != numRef) {
		printf("PTB-ERROR: Number of provided filtermode values %i doesn't match number of other primitives %i!\n", numFilterModes, numRef);
		PsychErrorExitMsg(PsychError_user, "Inconsistent number of arguments provided to Screen('DrawTextures').");
	}

	if (nc > 1 && nc != numRef) {
		printf("PTB-ERROR: Number of provided modulateColors %i doesn't match number of other primitives %i!\n", nc, numRef);
		PsychErrorExitMsg(PsychError_user, "Inconsistent number of arguments provided to Screen('DrawTextures').");
	}

	if (numAuxParams > 1 && numAuxParams != numRef) {
		printf("PTB-ERROR: Number of provided 'auxParameter' column vectors %i doesn't match number of other primitives %i!\n", numAuxParams, numRef);
		PsychErrorExitMsg(PsychError_user, "Inconsistent number of arguments provided to Screen('DrawTextures').");
	}

	// Assign optional override texture shader, if any provided:
	textureShader = -1;
    PsychCopyInIntegerArg(9, kPsychArgOptional, &textureShader);

	// Assign any other optional special flags:
    PsychCopyInIntegerArg(10, kPsychArgOptional, &specialFlags);

	// Ok, everything consistent so far.
	
	// Texture blitting loop:
	for (i=0; i < numRef; i++) {
		// Draw i'th texture:
		
		// Check if more than one texture provided. If not then the one single texture has been
		// setup already above:
		if (numTexs > 1) {
			// More than one texture handle provided: Need to allocate i'th one in:
			if(!IsWindowIndex((PsychWindowIndexType) texids[i])) {
				printf("PTB-ERROR: %i th entry in texture handle vector is not a valid handle!\n");
				PsychErrorExitMsg(PsychError_user, "Invalid texture handle provided to Screen('DrawTextures').");
			}

			// Get it:
			FindWindowRecord((PsychWindowIndexType) texids[i], &source);
			if(source->windowType!=kPsychTexture) {
				printf("PTB-ERROR: %i th entry in texture handle vector is not a valid handle!\n");
				PsychErrorExitMsg(PsychError_user, "The second argument supplied was not a texture handle!");
			}

			// Ok, we have our texture record in source:
		}
		
		// Source rectangle provided?
		if (numsrcRects > 1) {
			// Get i'th source rectangle:
			PsychCopyRect(sourceRect, &(srcRects[i*4]));
		} else if (numsrcRects == 1) {
			// Single source rect provided - get it:
			PsychCopyRect(sourceRect, &(srcRects[0]));
		} else {
			// No source rect provided: Take rectangle of current texture as srcRect:
			PsychCopyRect(sourceRect,source->clientrect);
		}
		
		// Skip this texture if sourceRect is an empty rect:
		if (IsPsychRectEmpty(sourceRect)) continue;
		
		// Destination rectangle provided?
		if (numdstRects > 1) {
			// Get i'th destination rectangle:
			PsychCopyRect(targetRect, &(dstRects[i*4]));
		} else if (numdstRects == 1) {
			// Single destination rect provided - get it:
			PsychCopyRect(targetRect, &(dstRects[0]));
		} else {
			// No destination rect provided: Center the current sourceRect in the current
			// target window and use that as destination:
            PsychCopyRect(tempRect, target->clientrect);
			PsychCenterRectInRect(sourceRect, tempRect, targetRect);
		}
		
		// Skip this texture if targetRect is an empty rect:
		if (IsPsychRectEmpty(targetRect)) continue;
		
		if (numAngles > 1) rotationAngle = rotationAngles[i];
		if (numFilterModes > 1) filterMode = filterModes[i];
		if (numAlphas > 1) globalAlpha = globalAlphas[i];
		
		// Disable alpha if modulateColor active:
		if (nc > 0) globalAlpha = DBL_MAX;

		// Pass auxParameters for current primitive in the auxShaderParams field.
		target->auxShaderParamsCount = numAuxComponents;
		if (numAuxParams > 0) {
			if (numAuxParams == 1) {
				target->auxShaderParams = auxParameters;
			}
			else {
				target->auxShaderParams = &(auxParameters[i * numAuxComponents]);
			}
		}
		else {
			target->auxShaderParams = NULL;
		}
		
		// Multiple modulateColors provided?
		if (nc > 1) {
			// Yes. Set it up as current vertex color: We submit to internal currentColor for
			// shader based color processing and via glColorXXX() for fixed pipe processing:
			if (mc==3) {
				if (colors) {
					// RGB double:
					glColor3dv(&(colors[i*3]));
					target->currentColor[0]=colors[i*3 + 0];
					target->currentColor[1]=colors[i*3 + 1];
					target->currentColor[2]=colors[i*3 + 2];
					target->currentColor[3]=1.0;
				}
				else {
					// RGB uint8:
					glColor3ubv(&(bytecolors[i*3]));
					target->currentColor[0]=((double) bytecolors[i*3 + 0] / 255.0);
					target->currentColor[1]=((double) bytecolors[i*3 + 1] / 255.0);
					target->currentColor[2]=((double) bytecolors[i*3 + 2] / 255.0);
					target->currentColor[3]=1.0;
				}
			}
			else {
				if (colors) {
					// RGBA double:
					glColor4dv(&(colors[i*4]));
					target->currentColor[0]=colors[i*4 + 0];
					target->currentColor[1]=colors[i*4 + 1];
					target->currentColor[2]=colors[i*4 + 2];
					target->currentColor[3]=colors[i*4 + 3];
				}
				else {
					// RGBA uint8:
					glColor4ubv(&(bytecolors[i*4]));
					target->currentColor[0]=((double) bytecolors[i*4 + 0] / 255.0);
					target->currentColor[1]=((double) bytecolors[i*4 + 1] / 255.0);
					target->currentColor[2]=((double) bytecolors[i*4 + 2] / 255.0);
					target->currentColor[3]=((double) bytecolors[i*4 + 3] / 255.0);
				}					
			}			
		}
		
		// Ok, everything assigned. Check parameters:
		if (filterMode<0 || filterMode>3) {
			PsychErrorExitMsg(PsychError_user, "filterMode needs to be 0 for nearest neighbour filter, or 1 for bilinear filter, or 2 for mipmapped filter or 3 for mipmapped-linear filter.");    
		}

		// Set rotation mode flag for texture matrix rotation if secialFlags is set accordingly:
		if (specialFlags & kPsychUseTextureMatrixForRotation) source->specialflags|=kPsychUseTextureMatrixForRotation;
		if (specialFlags & kPsychDontDoRotation) source->specialflags|=kPsychDontDoRotation;

		// Perform blit operation for i'th texture, either with or without an override texture shader applied:
		if (textureShader > -1) {
			backupShader = source->textureFilterShader;
			source->textureFilterShader = -1 * textureShader;
			PsychBlitTextureToDisplay(source, target, sourceRect, targetRect, rotationAngle, filterMode, globalAlpha);	
			source->textureFilterShader = backupShader;
		}
		else {
			PsychBlitTextureToDisplay(source, target, sourceRect, targetRect, rotationAngle, filterMode, globalAlpha);	
		}

		// Reset rotation mode flag:
		source->specialflags &= ~(kPsychUseTextureMatrixForRotation | kPsychDontDoRotation);

		// Next one...
	}

	target->auxShaderParams = NULL;
	target->auxShaderParamsCount = 0;

    // Mark end of drawing op. This is needed for single buffered drawing:
    PsychFlushGL(target);

    return(PsychError_none);
}