PsychError SCREENglLoadIdentity(void)  
{
    // If you change useString then also change the corresponding synopsis string in ScreenSynopsis.c
    static char useString[] = "Screen('glLoadIdentity', windowPtr);";
    static char synopsisString[] = "Reset an OpenGL matrix to its default identity setting. "
        "See <http://www.opengl.org/documentation/red_book_1.0/> Chapter 4 for detailed information.";
    static char seeAlsoString[] = "";	
    
    PsychWindowRecordType	*windowRecord;
    
    //all sub functions should have these two lines
    PsychPushHelp(useString, synopsisString,seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    //check for superfluous arguments
    PsychErrorExit(PsychCapNumInputArgs(1));        // The maximum number of inputs
    PsychErrorExit(PsychRequireNumInputArgs(1)); 	// Number of required 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);
    
    // Switch to windows OpenGL context:
    PsychSetGLContext(windowRecord); 
    // Execute it:
    glLoadIdentity();
    
    PsychTestForGLErrors();
    
    //All psychfunctions require this.
    return(PsychError_none);
}
PsychError SCREENTextStyle(void) 
{

    boolean						doSetStyle;
    PsychWindowRecordType		*windowRecord;
    int							oldTextStyle, newTextStyle;
    
    //all subfunctions should have these two lines.  
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    //check for valid number of arguments
    PsychErrorExit(PsychRequireNumInputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(2));   	
    PsychErrorExit(PsychCapNumOutputArgs(1)); 
    
    //Get the window record
    PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
    
    //Save the old text size value and return it.
    oldTextStyle=windowRecord->textAttributes.textStyle;
    PsychCopyOutDoubleArg(1, FALSE, (double)oldTextStyle);
    
    //Fetch and set the new size if it is specified. 
    doSetStyle= PsychCopyInIntegerArg(2, FALSE, &newTextStyle);
    if(doSetStyle)
        windowRecord->textAttributes.textStyle=newTextStyle;
        
    return(PsychError_none);

}
PsychError SCREENPixelSize(void) 
{
    int 			screenNumber;
    double 			depth;
    PsychWindowRecordType	*windowRecord; 
    
    //all sub functions should have these two lines
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    //check to see if the user supplied superfluous arguments
    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(1));
    
    //get specified screen number.
    if(PsychIsScreenNumberArg(1)){    
        PsychCopyInScreenNumberArg(1, TRUE, &screenNumber);
        depth=(double)PsychGetScreenDepthValue(screenNumber);
    }else if(PsychIsWindowIndexArg(1)){
        PsychAllocInWindowRecordArg(1,TRUE,&windowRecord);
        depth=(double)windowRecord->depth;
    }else
        PsychErrorExit(PsychError_invalidNumdex);
        
    //Allocate a return matrix and load it with the depth values.  
    PsychCopyOutDoubleArg(1, FALSE, depth);
    
    return(PsychError_none);	
}
Esempio n. 4
0
PsychError SCREENRect(void)  
{
	
	PsychWindowRecordType *windowRecord;
	int screenNumber;
	PsychRectType rect; 
    
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous arguments
	PsychErrorExit(PsychCapNumInputArgs(1));		//The maximum number of inputs
	PsychErrorExit(PsychRequireNumInputArgs(1));	//Insist that the argument be present.   
	PsychErrorExit(PsychCapNumOutputArgs(1));		//The maximum number of outputs

	if(PsychIsScreenNumberArg(1)){
		PsychCopyInScreenNumberArg(1, TRUE, &screenNumber);
		PsychGetScreenRect(screenNumber, rect);
		PsychCopyOutRectArg(1, FALSE, rect);
	}else if(PsychIsWindowIndexArg(1)){
        PsychAllocInWindowRecordArg(1, TRUE, &windowRecord);
        PsychOSProcessEvents(windowRecord, 0);		
        PsychCopyOutRectArg(1,FALSE, windowRecord->clientrect);
	}else
		PsychErrorExitMsg(PsychError_user, "Argument was recognized as neither a window index nor a screen pointer");
    
	return(PsychError_none);
}
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);
}
PsychError SCREENWindowSize(void)
{

    PsychWindowRecordType *windowRecord;
    int screenNumber;
    PsychRectType rect;
    double	rectWidth, rectHeight;

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

    //check for superfluous arguments
    PsychErrorExit(PsychCapNumInputArgs(1));		//The maximum number of inputs
    PsychErrorExit(PsychRequireNumInputArgs(1));	//Insist that the argument be present.
    PsychErrorExit(PsychCapNumOutputArgs(2));		//The maximum number of outputs

    if(PsychIsScreenNumberArg(1)) {
        PsychCopyInScreenNumberArg(1, TRUE, &screenNumber);
        PsychGetScreenRect(screenNumber, rect);
        rectWidth=PsychGetWidthFromRect(rect);
        rectHeight=PsychGetHeightFromRect(rect);
        PsychCopyOutDoubleArg(1, kPsychArgOptional, rectWidth);
        PsychCopyOutDoubleArg(2, kPsychArgOptional, rectHeight);
    } else if(PsychIsWindowIndexArg(1)) {
        PsychAllocInWindowRecordArg(1, TRUE, &windowRecord);
        PsychOSProcessEvents(windowRecord, 0);

        rectWidth=PsychGetWidthFromRect(windowRecord->rect);
        rectHeight=PsychGetHeightFromRect(windowRecord->rect);

        if (windowRecord->specialflags & kPsychHalfWidthWindow) {
            // Special case for stereo: Only half the real window width:
            rectWidth = rectWidth / 2;
        }

        if (windowRecord->specialflags & kPsychHalfHeightWindow) {
            // Special case for stereo: Only half the real window width:
            rectHeight = rectHeight / 2;
        }

        PsychCopyOutDoubleArg(1, kPsychArgOptional, rectWidth);
        PsychCopyOutDoubleArg(2, kPsychArgOptional, rectHeight);
    } else
        PsychErrorExitMsg(PsychError_user, "Argument was recognized as neither a window index nor a screen pointer");

    return(PsychError_none);
}
PsychError SCREENglRotate(void)  
{
    // If you change useString then also change the corresponding synopsis string in ScreenSynopsis.c
    static char useString[] = "Screen('glRotate', windowPtr, angle, [rx = 0], [ry = 0] ,[rz = 1]);";
    //                                            1          2       3         4         5
    static char synopsisString[] = "Define a rotation transform by an angle of 'angle' degrees around the "
        "axis defined by the vector (rx,ry,rz) in space, relative to the enclosing reference frame."
        "See <http://www.opengl.org/documentation/red_book_1.0/> Chapter 4 for detailed information.";
    static char seeAlsoString[] = "";	
    
    PsychWindowRecordType	*windowRecord;
    double                      rx, ry, rz;
    double                      angle;
    
    // Default to rotation around z-axis, aka in-plane rotation:
    rx=ry=0;
    rz=1;
    // Default to a non-rotation (zero degrees):
    angle=0;
    
    //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(PsychRequireNumInputArgs(2));    // Number of required 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);

    // Fetch rotation angle:
    PsychCopyInDoubleArg(2, TRUE, &angle);
    
    // Fetch rotation vector:
    PsychCopyInDoubleArg(3, FALSE, &rx);
    PsychCopyInDoubleArg(4, FALSE, &ry);
    PsychCopyInDoubleArg(5, FALSE, &rz);
    
    // Switch to windows OpenGL context:
    PsychSetGLContext(windowRecord); 
    
    // Execute it:
    glRotated(angle, rx, ry, rz);
    PsychTestForGLErrors();
    
    //All psychfunctions require this.
    return(PsychError_none);
}
PsychError SCREENglPushMatrix(void)  
{
        // If you change useString then also change the corresponding synopsis string in ScreenSynopsis.c
        static char useString[] = "Screen('glPushMatrix', windowPtr);";
        static char synopsisString[] = "Store a backup copy of active current OpenGL matrix on the matrix stack for later reuse. "
            "The capacity of the matrix backup stack is limited, typically not more than 27 slots. For each call to glPushMatrix "
            "you need to call glPopMatrix at the appropriate place to avoid overflowing the stack. "
            "See <http://www.opengl.org/documentation/red_book_1.0/> Chapter 4 for detailed information.";
        static char seeAlsoString[] = "";	
    
	PsychWindowRecordType	*windowRecord;
        GLint stack_cur, stack_max;
    
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous arguments
	PsychErrorExit(PsychCapNumInputArgs(1));        // The maximum number of inputs
        PsychErrorExit(PsychRequireNumInputArgs(1)); 	// Number of required 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);
        
        // Switch to windows OpenGL context:
	PsychSetGLContext(windowRecord); 
        glMatrixMode(GL_MODELVIEW);
        
        // Compare current fill level of matrix stack with maximum level: We reserve five
        // stack-slots for PTB internal use, so at least that needs to be free before push.

        glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &stack_max);
        glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &stack_cur);
        if (stack_max - stack_cur < 6) {
            printf("\nCouldn't push OpenGL-Modelview matrix because matrix stack is full! The most common reason is\n");
            printf("forgetting to call glPopMatrix a matching number of times... \n");
            printf("The maximum number of pushable matrices is %i -- Please check your code.\n", stack_max - 5);
            PsychErrorExitMsg(PsychError_user, "Too many calls to glPushMatrix. Imbalance?");
        }
        
        // Execute push op:
        glPushMatrix();        
        
        PsychTestForGLErrors();
        
 	//All psychfunctions require this.
	return(PsychError_none);
}
PsychError SCREENTextStyle(void) 
{
    psych_bool						doSetStyle, foundFont;
    PsychWindowRecordType		*windowRecord;
    int							oldTextStyle, newTextStyle;

#if PSYCH_SYSTEM == PSYCH_OSX
    PsychFontStructType			*fontRecord;
#endif

    //all subfunctions should have these two lines.  
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    //check for valid number of arguments
    PsychErrorExit(PsychRequireNumInputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(2));   	
    PsychErrorExit(PsychCapNumOutputArgs(1)); 
    
    //Get the window record
    PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
    
    //Save the old text size value and return it.
    oldTextStyle=windowRecord->textAttributes.textStyle;
    PsychCopyOutDoubleArg(1, FALSE, (double)oldTextStyle);
    
    //Fetch and set the new size if it is specified. 
    doSetStyle= PsychCopyInIntegerArg(2, FALSE, &newTextStyle);
    if (doSetStyle) {
      windowRecord->textAttributes.needsRebuild|=(windowRecord->textAttributes.textStyle != newTextStyle) ? TRUE : FALSE;
      windowRecord->textAttributes.textStyle=newTextStyle;
	  
	  #if PSYCH_SYSTEM == PSYCH_OSX
	  // Need to update font name and number from changed style on OS/X:
	  foundFont = PsychGetFontRecordFromFontFamilyNameAndFontStyle((char*) windowRecord->textAttributes.textFontName, windowRecord->textAttributes.textStyle, &fontRecord);
	  if (foundFont) {
		strncpy((char*) windowRecord->textAttributes.textFontName, (const char*) fontRecord->fontFMFamilyName, 255);
		windowRecord->textAttributes.textFontNumber= fontRecord->fontNumber;
	  }
	  else {
		// Failed! Revert to old setting:
		windowRecord->textAttributes.textStyle = oldTextStyle;
	  }
	  
	  #endif
    }
	
    return(PsychError_none);
}
Esempio n. 12
0
PsychError SCREENWindowSize(void)  
{
	PsychWindowRecordType *windowRecord;
	int screenNumber;
	double	rectWidth, rectHeight;
    long fbWidth, fbHeight;
    int realFBSize = 0;
    
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous arguments
	PsychErrorExit(PsychCapNumInputArgs(2));		//The maximum number of inputs
	PsychErrorExit(PsychRequireNumInputArgs(1));	//Insist that the argument be present.   
	PsychErrorExit(PsychCapNumOutputArgs(2));		//The maximum number of outputs

    // Get optional 'realFBSize' flag: Defaults to zero.
    PsychCopyInIntegerArg(2, FALSE, &realFBSize);

	if(PsychIsScreenNumberArg(1)){
		PsychCopyInScreenNumberArg(1, TRUE, &screenNumber);
        if (realFBSize) {
            // Physical size in pixels:
            PsychGetScreenPixelSize(screenNumber, &fbWidth, &fbHeight);
        }
        else {
            // Logical size in points:
            PsychGetScreenSize(screenNumber, &fbWidth, &fbHeight);
        }
		PsychCopyOutDoubleArg(1, kPsychArgOptional, fbWidth);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, fbHeight);
	}else if(PsychIsWindowIndexArg(1)){
		PsychAllocInWindowRecordArg(1, TRUE, &windowRecord);
		PsychOSProcessEvents(windowRecord, 0);

		rectWidth=PsychGetWidthFromRect((realFBSize) ? windowRecord->rect : windowRecord->clientrect);
		rectHeight=PsychGetHeightFromRect((realFBSize) ? windowRecord->rect : windowRecord->clientrect);

		PsychCopyOutDoubleArg(1, kPsychArgOptional, rectWidth);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, rectHeight);
	}else
		PsychErrorExitMsg(PsychError_user, "Argument was recognized as neither a window index nor a screen pointer");

	return(PsychError_none);
}
PsychError SCREENglPopMatrix(void)  
{
    // If you change useString then also change the corresponding synopsis string in ScreenSynopsis.c
    static char useString[] = "Screen('glPopMatrix', windowPtr);";
    static char synopsisString[] = "Restore an OpenGL matrix by fetching it from the matrix stack. "
        "See <http://www.opengl.org/documentation/red_book_1.0/> Chapter 4 for detailed information.";
    static char seeAlsoString[] = "";	
    
    PsychWindowRecordType	*windowRecord;
    GLint stack_cur;
    
    //all sub functions should have these two lines
    PsychPushHelp(useString, synopsisString,seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    //check for superfluous arguments
    PsychErrorExit(PsychCapNumInputArgs(1));        // The maximum number of inputs
    PsychErrorExit(PsychRequireNumInputArgs(1)); 	// Number of required 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);
    
    // Switch to windows OpenGL context:
    PsychSetGLContext(windowRecord); 
    glMatrixMode(GL_MODELVIEW);
    
    // Compare current fill level of matrix stack with maximum level: We reserve five
    // stack-slots for PTB internal use, so at least that needs to be free before push.

    glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &stack_cur);
    if (stack_cur < 2) {
        printf("\nCouldn't pop matrix from top of OpenGL-Modelview matrix stack, because matrix stack is empty! The most common reason is\n");
        printf("that you tried to call glPopMatrix more often than you called glPushMatrix -- Please check your code.\n");
        PsychErrorExitMsg(PsychError_user, "Too many calls to glPopMatrix. Imbalance?!?");
    }

    // Execute pop operation:
    glPopMatrix();
    
    PsychTestForGLErrors();
    
    //All psychfunctions require this.
    return(PsychError_none);
}
Esempio n. 14
0
PsychError SCREENTextFont(void) 
{

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

}
PsychError SCREENglScale(void)  
{
    // If you change useString then also change the corresponding synopsis string in ScreenSynopsis.c
    static char useString[] = "Screen('glScale', windowPtr, sx, sy [, sz]);";
    //                                           1          2   3     4
    static char synopsisString[] = "Define a scale transform by (sx, sy, sz) in space, relative to the enclosing reference frame."
        "See <http://www.opengl.org/documentation/red_book_1.0/> Chapter 4 for detailed information.";
    static char seeAlsoString[] = "";	
    
    PsychWindowRecordType	*windowRecord;
    double                      sx, sy, sz;
    
    // Default to non-scale, aka scale by 1.0:
    sx=sy=sz=1.0f;
    
    //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(PsychRequireNumInputArgs(3));    // Number of required 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);
    
    // Fetch translation vector:
    PsychCopyInDoubleArg(2, FALSE, &sx);
    PsychCopyInDoubleArg(3, FALSE, &sy);
    PsychCopyInDoubleArg(4, FALSE, &sz);
    
    // Switch to windows OpenGL context:
    PsychSetGLContext(windowRecord); 
    
    // Execute it:
    glScaled(sx, sy, sz);
    PsychTestForGLErrors();
    
    //All psychfunctions require this.
    return(PsychError_none);
}
Esempio n. 16
0
PsychError SCREENTextMode(void) 
{

    PsychTextDrawingModeType		newCopyMode;
    Str255							oldCopyModeName; 
    char							*newCopyModeName;
    psych_bool							doSetMode;
    PsychWindowRecordType			*windowRecord;
    psych_bool							nameError;                           
    
    //all subfunctions should have these two lines.  
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    //check for valid number of arguments
    PsychErrorExit(PsychRequireNumInputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(2));   	
    PsychErrorExit(PsychCapNumOutputArgs(1)); 
    
    //Get the window record
    PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
    
    //Get the old copy mode & its name
    PsychGetTextDrawingModeNameFromTextDrawingModeConstant(oldCopyModeName, 255, windowRecord->textAttributes.textMode);
    PsychCopyOutCharArg(1, FALSE, oldCopyModeName);
    
    //Get the copy new mode string 
    doSetMode= PsychAllocInCharArg(2, FALSE, &newCopyModeName);
    if(doSetMode){
        nameError=PsychGetTextDrawingModeConstantFromTextDrawingModeName(&newCopyMode, newCopyModeName);
        if(nameError)
            PsychErrorExitMsg(PsychError_user, "Invalid text copy mode.  See Screen('TextModes') for a list of allowable modes");
		windowRecord->textAttributes.needsRebuild|=(windowRecord->textAttributes.textMode != newCopyMode) ? TRUE : FALSE;
        windowRecord->textAttributes.textMode=newCopyMode;	
    }
	
    return(PsychError_none);
}
PsychError SCREENGlobalRect(void)  
{	
	int						screenNumber;
	PsychWindowRecordType	*windowRecord;
	PsychRectType			rect; 
    
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous arguments
	PsychErrorExit(PsychCapNumInputArgs(1));			
	PsychErrorExit(PsychRequireNumInputArgs(1));		 
	PsychErrorExit(PsychCapNumOutputArgs(1));			

	if(PsychIsScreenNumberArg(1)) {
		// Real screen id: Get screens global rect and return it:
		PsychCopyInScreenNumberArg(1, TRUE, &screenNumber);
		PsychGetGlobalScreenRect(screenNumber, rect);
		PsychCopyOutRectArg(1, FALSE, rect);
	}
	else if(PsychIsWindowIndexArg(1)) {
		// Window:
		PsychAllocInWindowRecordArg(1, TRUE, &windowRecord);

		//  Onscreen?
		if (PsychIsOnscreenWindow(windowRecord)) {
			PsychCopyOutRectArg(1, FALSE, windowRecord->globalrect);
		}
		else {
			PsychCopyOutRectArg(1, FALSE, windowRecord->rect);
		}
	}
	else PsychErrorExitMsg(PsychError_user, "Argument was recognized as neither a window index nor a screen pointer");

	return(PsychError_none);
}
PsychError SCREENSetOpenGLTextureFromMemPointer(void) 
{
    PsychWindowRecordType *windowRecord, *textureRecord;
    int w, h, d, testarg, upsidedown, glinternalformat, glexternaltype, glexternalformat;
    double doubleMemPtr;
    GLenum target = 0;
    w=h=d=-1;
    doubleMemPtr = 0;
    upsidedown = 0;

    //all subfunctions should have these two lines.  
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    PsychErrorExit(PsychCapNumInputArgs(11));     // The maximum number of inputs
    PsychErrorExit(PsychRequireNumInputArgs(5)); // The required number of inputs
    PsychErrorExit(PsychCapNumOutputArgs(2));    // 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 texture record from the texture record argument.
    // Check if either none ( [] or '' ) or the special value zero was
    // provided as Psychtoolbox textureHandle. In that case, we create a new
    // empty texture record instead of reusing an existing one.
    testarg=0;
    PsychCopyInIntegerArg(2, FALSE, &testarg);
    if (testarg==0) {
        // No valid textureHandle provided. Create a new empty textureRecord.
        PsychCreateWindowRecord(&textureRecord);
        textureRecord->windowType=kPsychTexture;
        textureRecord->screenNumber = windowRecord->screenNumber;
        textureRecord->targetSpecific.contextObject = windowRecord->targetSpecific.contextObject;
        textureRecord->targetSpecific.deviceContext = windowRecord->targetSpecific.deviceContext;
        textureRecord->targetSpecific.glusercontextObject = windowRecord->targetSpecific.glusercontextObject;
		
		textureRecord->colorRange = windowRecord->colorRange;
		// Copy imaging mode flags from parent:
		textureRecord->imagingMode = windowRecord->imagingMode;

        // Mark it valid and return handle to userspace:
        PsychSetWindowRecordValid(textureRecord);
    }
    else {
        // None of the special values provided. We assume its a handle to a valid
        // and existing PTB texture and try to retrieve the textureRecord:
        PsychAllocInWindowRecordArg(2, TRUE, &textureRecord);
    }
    
    // Is it  a textureRecord?
    if (!PsychIsTexture(textureRecord)) {
        PsychErrorExitMsg(PsychError_user, "You tried to set texture information on something else than a texture!");
    }
    
    // Query double-encoded memory pointer:
    PsychCopyInDoubleArg(3, TRUE, &doubleMemPtr);
    
    // Query width:
    PsychCopyInIntegerArg(4, TRUE, &w);

    // Query height:
    PsychCopyInIntegerArg(5, TRUE, &h);

    // Query depth:
    PsychCopyInIntegerArg(6, TRUE, &d);

    // Query (optional) upsidedown - flag:
    PsychCopyInIntegerArg(7, FALSE, &upsidedown);
    
    // Query (optional) OpenGL texture target:
    PsychCopyInIntegerArg(8, FALSE, (int*) &target);
 
    // Query (optional) full format spec:
    glinternalformat = 0;
    PsychCopyInIntegerArg(9, FALSE, &glinternalformat);
    if (glinternalformat>0) {
      // Ok copy the (now non-optional) remaining format spec:
      PsychCopyInIntegerArg(10, TRUE, &glexternalformat);
      PsychCopyInIntegerArg(11, TRUE, &glexternaltype);      
    }

    // Safety checks:
    if (doubleMemPtr == 0) {
        PsychErrorExitMsg(PsychError_user, "You tried to set invalid (NULL) imagePtr.");
    }

    if (w<=0) {
        PsychErrorExitMsg(PsychError_user, "You tried to set invalid (negative) texture width.");
    }

    if (h<=0) {
        PsychErrorExitMsg(PsychError_user, "You tried to set invalid (negative) texture height.");
    }
    
    if (d<=0) {
        PsychErrorExitMsg(PsychError_user, "You tried to set invalid (negative) texture depth.");
    }
    
    if (d>4) {
        PsychErrorExitMsg(PsychError_user, "You tried to set invalid (greater than four) texture depth.");
    }

    if (target!=0 && target!=GL_TEXTURE_RECTANGLE_EXT && target!=GL_TEXTURE_2D) {
        PsychErrorExitMsg(PsychError_user, "You tried to set invalid texture target.");
    }

    // Activate OpenGL rendering context of windowRecord and make it the active drawing target:
    PsychSetGLContext(windowRecord);
    PsychSetDrawingTarget(windowRecord);
    PsychTestForGLErrors();

    // Ok, setup texture record for texture:
    PsychInitWindowRecordTextureFields(textureRecord);
    textureRecord->depth = d * 8;
	textureRecord->nrchannels = d;
    PsychMakeRect(textureRecord->rect, 0, 0, w, h);

    // Override texture target, if one was provided:
    if (target!=0) textureRecord->texturetarget = target;

    // Orientation is normally set to 2 - like an upright Offscreen window texture.
    // If upsidedown flag is set, then we do 3 - an upside down Offscreen window texture.
    textureRecord->textureOrientation = (upsidedown>0) ? 3 : 2;
    
    if (glinternalformat!=0) {
      textureRecord->textureinternalformat = glinternalformat;
      textureRecord->textureexternalformat = glexternalformat;
      textureRecord->textureexternaltype = glexternaltype;
    }

    // Setting memsize to zero prevents unwanted free() operation in PsychDeleteTexture...
    textureRecord->textureMemorySizeBytes = 0;

    // This will retrieve an OpenGL compatible pointer to the raw pixel data and assign it to our texmemptr:
    textureRecord->textureMemory = (GLuint*) PsychDoubleToPtr(doubleMemPtr);
    // printf("InTexPtr %p , %.20e", PsychDoubleToPtr(doubleMemPtr), doubleMemPtr);

    // Let PsychCreateTexture() do the rest of the job of creating, setting up and
    // filling an OpenGL texture with memory buffers image content:
    PsychCreateTexture(textureRecord);

    // Return new (or old) PTB textureHandle for this texture:
    PsychCopyOutDoubleArg(1, FALSE, textureRecord->windowIndex);
    PsychCopyOutRectArg(2, FALSE, textureRecord->rect);

    // Done.
    return(PsychError_none);
}
Esempio n. 19
0
PsychError SCREENGetImage(void) 
{
	PsychRectType   windowRect,sampleRect;
	int 			nrchannels, ix, iy, sampleRectWidth, sampleRectHeight, invertedY, redReturnIndex, greenReturnIndex, blueReturnIndex, alphaReturnIndex, planeSize;
	int				viewid;
	ubyte 			*returnArrayBase, *redPlane, *greenPlane, *bluePlane, *alphaPlane;
	float 			*dredPlane, *dgreenPlane, *dbluePlane, *dalphaPlane;
	double 			*returnArrayBaseDouble;
	PsychWindowRecordType	*windowRecord;
	GLboolean		isDoubleBuffer, isStereo;
	char*           buffername = NULL;
	boolean			floatprecision = FALSE;
	GLenum			whichBuffer = 0; 
	
	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//cap the numbers of inputs and outputs
	PsychErrorExit(PsychCapNumInputArgs(5));   //The maximum number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(1));  //The maximum number of outputs
	
	// Get windowRecord for this window:
	PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
	
	// Set window as drawingtarget: Even important if this binding is changed later on!
	// We need to make sure all needed transitions are done - esp. in non-imaging mode,
	// so backbuffer is in a useable state:
	PsychSetDrawingTarget(windowRecord);
	
	// Disable shaders:
	PsychSetShader(windowRecord, 0);

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

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

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

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

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

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

    const char *valuatorInfo[]={"label", "min", "max", "resolution", "mode", "sourceID"};
    int numValuatorStructFieldNames = 6;
    int numIValuators = 0;
    PsychGenericScriptType *valuatorStruct = NULL;

#if PSYCH_SYSTEM == PSYCH_OSX
	Point		mouseXY;
	UInt32		buttonState;
	double		*buttonArray;
	int		numButtons, i;
	psych_bool	doButtonArray;
	PsychWindowRecordType *windowRecord;
	
	//all subfunctions should have these two lines.  
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//cap the numbers of inputs and outputs
	PsychErrorExit(PsychCapNumInputArgs(3));   //The maximum number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(6));  //The maximum number of outputs
	
	//Buttons.  
	// The only way I know to detect the  number number of mouse buttons is directly via HID.  The device reports
	//that information but OS X seems to ignore it above the level of the HID driver, that is, no OS X API above the HID driver
	//exposes it.  So GetMouse.m function calls PsychHID detect the number of buttons and then passes that value to GetMouseHelper 
	//which returns that number of button values in a vector.      
	PsychCopyInIntegerArg(1, kPsychArgRequired, &numButtons);
	if(numButtons > 32)
		PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "numButtons must not exceed 32");

	// Special codes -10 to -15? --> Console keyboard queries:
	if(numButtons <= -10 && numButtons >= -15) {
		ConsoleInputHelper((int) numButtons);
		return(PsychError_none);
	}

	if(numButtons < 1) 
		PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "numButtons must exceed 1");

	doButtonArray=PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int)numButtons, (int)1, &buttonArray);
	if(doButtonArray){
		buttonState=GetCurrentButtonState();
		for(i=0;i<numButtons;i++)
			buttonArray[i]=(double)(buttonState & (1<<i));
	}
			
	// Get cursor position:
#ifndef __LP64__
    // 32-Bit Carbon version:
	GetGlobalMouse(&mouseXY);
	PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)mouseXY.h);
	PsychCopyOutDoubleArg(2, kPsychArgOptional, (double)mouseXY.v);
#else
    // 64-Bit HIToolbox version (OSX 10.5 and later):
    HIPoint outPoint;
    HIGetMousePosition(kHICoordSpaceScreenPixel, NULL, &outPoint);
	PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) outPoint.x);
	PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) outPoint.y);
#endif
	// Return optional keyboard input focus status:
	if (numButtons > 0) {
		// Window provided?
        // We only have the function GetUserFocusWindow on 32-Bit Carbon.
        // We have a drop-in replacement in OSX/PsychCocoaGlue.c for 64-Bit Cocoa.
		if (PsychIsWindowIndexArg(2)) {
			// Yes: Check if it has focus.
			PsychAllocInWindowRecordArg(2, TRUE, &windowRecord);
			if (!PsychIsOnscreenWindow(windowRecord)) {
				PsychErrorExitMsg(PsychError_user, "Provided window handle isn't an onscreen window, as required.");
			}

			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) (GetUserFocusWindow() == windowRecord->targetSpecific.windowHandle) ? 1 : 0);
		} else
        {
			// No. Just always return "has focus":
			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) 1);
		}
	}

	// Return optional valuator values: Unimplemented on OS/X. Just return an empty matrix.
	// The buttonArray is just a dummy assignment without any meaning.
	PsychCopyOutDoubleMatArg(5, kPsychArgOptional, (int) 1, (int) 0, (int) 1, buttonArray);
	PsychCopyOutDoubleMatArg(6, kPsychArgOptional, (int) 1, (int) 0, (int) 1, buttonArray);
#endif

#if PSYCH_SYSTEM == PSYCH_WINDOWS
	static unsigned char disabledKeys[256];
	static unsigned char firsttime = 1;
	int keysdown, i, priorityLevel;
	unsigned char keyState[256];
	double* buttonArray;
	double numButtons, timestamp;
	PsychNativeBooleanType* buttonStates;
	POINT		point;
	HANDLE	   currentProcess;
	DWORD   oldPriority = NORMAL_PRIORITY_CLASS;
    const  DWORD   realtime_class = REALTIME_PRIORITY_CLASS;
	PsychWindowRecordType *windowRecord;

	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

	// Retrieve optional number of mouse buttons:
	numButtons = 0;
	PsychCopyInDoubleArg(1, FALSE, &numButtons);

	// Are we operating in 'GetMouseHelper' mode? numButtons>=0 indicates this.
	if (numButtons>=0) {
		// GetMouse-Mode: Return mouse button states and mouse cursor position:

		PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int)3, (int)1, &buttonArray);
		// Query and return mouse button state:
		PsychGetMouseButtonState(buttonArray);
		// Query and return cursor position in global coordinates:
		GetCursorPos(&point);
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) point.x);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) point.y);
		
		// Window provided?
		if (PsychIsWindowIndexArg(2)) {
			// Yes: Check if it has focus.
			PsychAllocInWindowRecordArg(2, TRUE, &windowRecord);
			if (!PsychIsOnscreenWindow(windowRecord)) {
				PsychErrorExitMsg(PsychError_user, "Provided window handle isn't an onscreen window, as required.");
			}

			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) (GetForegroundWindow() == windowRecord->targetSpecific.windowHandle) ? 1 : 0);
		} else {
			// No. Just always return "has focus":
			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) 1);
		}		

		// Return optional valuator values: Unimplemented on Windows. Just return an empty matrix.
		// The &timestamp is just a dummy assignment without any meaning.
		PsychCopyOutDoubleMatArg(5, kPsychArgOptional, (int) 1, (int) 0, (int) 1, &timestamp);
		PsychCopyOutDoubleMatArg(6, kPsychArgOptional, (int) 1, (int) 0, (int) 1, buttonArray);
	}
	else {
	  // 'KeyboardHelper' mode: We implement either KbCheck() or KbWait() via X11.
	  // This is a hack to provide keyboard queries until a PsychHID() implementation
	  // for Microsoft Windows is available...

		// Special codes -10 to -15? --> Console keyboard queries:
		if(numButtons <= -10 && numButtons >= -15) {
			ConsoleInputHelper((int) numButtons);
			return(PsychError_none);
		}
		
	  if (firsttime) {
			// First time init:
			firsttime = 0;
			memset(keyState, 0, sizeof(keyState));
			memset(disabledKeys, 0, sizeof(disabledKeys));
			// These keycodes are always disabled: 0, 255:
			disabledKeys[0]=1;
			disabledKeys[255]=1;
			// Mouse buttone (left, right, middle) are also disabled by default:
			disabledKeys[1]=1;
			disabledKeys[2]=1;
			disabledKeys[4]=1;
	  }

	  if (numButtons==-1 || numButtons==-2) {
	    // KbCheck()/KbWait() mode
	    do {
	      // Reset overall key state to "none pressed":
	      keysdown=0;

	      // Request current time of query:
	      PsychGetAdjustedPrecisionTimerSeconds(&timestamp);

			// Query state of all keys:
			for(i=1;i<255;i++){
				keyState[i] = (GetAsyncKeyState(i) & -32768) ? 1 : 0;
			}

	      // Disable all keys that are registered in disabledKeys. Check if
			// any non-disabled key is down.
	      for (i=0; i<256; i++) {
				if (disabledKeys[i]>0) keyState[i] = 0;
				keysdown+=(unsigned int) keyState[i];
	      }

	      // We repeat until any key pressed if in KbWait() mode, otherwise we
	      // exit the loop after first iteration in KbCheck mode.
	      if ((numButtons==-1) || ((numButtons==-2) && (keysdown>0))) break;

	      // Sleep for a millisecond before next KbWait loop iteration:
	      PsychWaitIntervalSeconds(0.001);

	    } while(1);

	    if (numButtons==-2) {
	      // KbWait mode: Copy out time value.
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, timestamp);
	    }
	    else {
	      // KbCheck mode:
	      
	      // Copy out overall keystate:
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, (keysdown>0) ? 1 : 0);

	      // Copy out timestamp:
	      PsychCopyOutDoubleArg(2, kPsychArgOptional, timestamp);	      

	      // Copy out keyboard state:
	      PsychAllocOutBooleanMatArg(3, kPsychArgOptional, 1, 256, 1, &buttonStates);

	      // Build 256 elements return vector:
	      for(i=0; i<255; i++) {
		  		buttonStates[i] = (PsychNativeBooleanType)((keyState[i+1]) ? 1 : 0);
	      }
			// Special case: Null out last element:
			buttonStates[255] = (PsychNativeBooleanType) 0;
	    }
	  }
	  
	  if (numButtons==-3) {
		// Priority() - helper mode: The 2nd argument is the priority level:

		// Determine our processID:
		currentProcess = GetCurrentProcess();
    
		// Get current scheduling policy:
		oldPriority = GetPriorityClass(currentProcess);
		
		// Map to PTB's scheme:
		switch(oldPriority) {
			case NORMAL_PRIORITY_CLASS:
				priorityLevel = 0;
			break;

			case HIGH_PRIORITY_CLASS:
				priorityLevel = 1;
			break;

			case REALTIME_PRIORITY_CLASS:
				priorityLevel = 2;
			break;

			default:
				priorityLevel = 0;
		}
        
		// Copy it out as optional return argument:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) priorityLevel);
		
		// Query if a new level should be set:
		priorityLevel = -1;
		PsychCopyInIntegerArg(2, kPsychArgOptional, &priorityLevel);

		// Priority level provided?
		if (priorityLevel > -1) {
			// Map to new scheduling class:
			if (priorityLevel > 2) PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "Invalid Priority level: Requested Priority() level must not exceed 2.");

			switch(priorityLevel) {
				case 0: // Standard scheduling:
					SetPriorityClass(currentProcess, NORMAL_PRIORITY_CLASS);

					// Disable any MMCSS scheduling for us:
					PsychSetThreadPriority((psych_thread*) 0x1, 0, 0);
				break;
				
				case 1: // High priority scheduling:
					SetPriorityClass(currentProcess, HIGH_PRIORITY_CLASS);

					// Additionally try to schedule us MMCSS: This will lift us roughly into the
					// same scheduling range as REALTIME_PRIORITY_CLASS, even if we are non-admin users
					// on Vista and Windows-7 and later, however with a scheduler safety net applied.
					PsychSetThreadPriority((psych_thread*) 0x1, 10, 0);
				break;
				
				case 2: // Realtime scheduling:
					// This can fail if Matlab is not running under a user account with proper permissions:
					if ((0 == SetPriorityClass(currentProcess, REALTIME_PRIORITY_CLASS)) || (REALTIME_PRIORITY_CLASS != GetPriorityClass(currentProcess))) {
						// Failed to get RT-Scheduling. Let's try at least high priority scheduling:
						SetPriorityClass(currentProcess, HIGH_PRIORITY_CLASS);
						
						// Additionally try to schedule us MMCSS: This will lift us roughly into the
						// same scheduling range as REALTIME_PRIORITY_CLASS, even if we are non-admin users
						// on Vista and Windows-7 and later, however with a scheduler safety net applied.
						PsychSetThreadPriority((psych_thread*) 0x1, 10, 0);
					}
				break;
			}
		}
		// End of Priority() helper for Win32.
	  }
	}
#endif
	
#if PSYCH_SYSTEM == PSYCH_LINUX
	double myvaluators[100];
	int    numvaluators;
	unsigned char keys_return[32];
	char* keystring;
	PsychGenericScriptType *kbNames;
	CGDirectDisplayID dpy;
	Window rootwin, childwin, mywin;
	int i, j, mx, my, dx, dy;
	double mxd, myd, dxd, dyd;
	unsigned int mask_return;
	double timestamp;
	int numButtons;
	double* buttonArray;
	PsychNativeBooleanType* buttonStates;
	int keysdown;
	XEvent event_return;
	XKeyPressedEvent keypressevent;
	int screenNumber;
	int priorityLevel;
	struct sched_param schedulingparam;
	PsychWindowRecordType *windowRecord;
	int mouseIndex;
	XIButtonState buttons_return;
	XIModifierState modifiers_return;
	XIGroupState group_return;

	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

	PsychCopyInIntegerArg(1, kPsychArgRequired, &numButtons);

	// Retrieve optional screenNumber argument:
	if (numButtons!=-5) {
		screenNumber = 0;
		if (PsychIsScreenNumberArg(2)) {
			PsychCopyInScreenNumberArg(2, FALSE, &screenNumber);
		}

		// Map screenNumber to X11 display handle and screenid:
		PsychGetCGDisplayIDFromScreenNumber(&dpy, screenNumber);

		if (PsychIsWindowIndexArg(2)) {
			PsychAllocInWindowRecordArg(2, TRUE, &windowRecord);
			if (!PsychIsOnscreenWindow(windowRecord)) {
				PsychErrorExitMsg(PsychError_user, "Provided window handle isn't an onscreen window, as required.");
			}

			screenNumber = windowRecord->screenNumber;
			mywin = windowRecord->targetSpecific.xwindowHandle;

			// Map screenNumber to X11 display handle and screenid:
			PsychGetCGDisplayIDFromScreenNumber(&dpy, screenNumber);

		} else {
			mywin = RootWindow(dpy, PsychGetXScreenIdForScreen(screenNumber));
		}
	}

	// Default to "old school" mouse query - System default mouse via X core protocol:
	mouseIndex = -1;
	PsychCopyInIntegerArg(3, FALSE, &mouseIndex);

	// Are we operating in 'GetMouseHelper' mode? numButtons>=0 indicates this.
	if (numButtons>=0) {
	  // Mouse pointer query mode:
	  numvaluators = 0;

	  if (mouseIndex >= 0) {
		// XInput-2 query for handling of multiple mouse pointers:

		// Query input device list for screen:
		int nDevices;
		XIDeviceInfo* indevs = PsychGetInputDevicesForScreen(screenNumber, &nDevices);

		// Sanity check:
		if (NULL == indevs) PsychErrorExitMsg(PsychError_user, "Sorry, your system does not support individual mouse pointer queries.");
		if (mouseIndex >= nDevices) PsychErrorExitMsg(PsychError_user, "Invalid 'mouseIndex' provided. No such device.");
		if ((indevs[mouseIndex].use != XIMasterPointer) && (indevs[mouseIndex].use != XISlavePointer) && (indevs[mouseIndex].use != XIFloatingSlave)) {
			PsychErrorExitMsg(PsychError_user, "Invalid 'mouseIndex' provided. Not a pointer device.");
		}

		// We requery the device info struct to retrieve updated live device state:
		// Crucial for slave pointers to get any state at all, but also needed on
		// master pointers to get the state of additional valuators, e.g., pen pressure,
		// touch area, tilt etc. for digitizer tablets, touch pads etc. For master pointers,
		// the primary 2 axis for 2D (x,y) position and the button/modifier state will be
		// queried via a dedicated XIQueryPointer() call, so that info gets overriden.
		indevs = XIQueryDevice(dpy, indevs[mouseIndex].deviceid, &numButtons);
		modifiers_return.effective = 0;

		// Query real number of mouse buttons and the raw button and axis state
		// stored inside the device itself. This is done mostly because slave pointer
		// devices don't support XIQueryPointer() so we get their relevant info from the
		// XIDeviceInfo struct itself:
		numButtons = 0;
		numvaluators = 0;
		memset(myvaluators, 0, sizeof(myvaluators));

		if (PsychIsArgPresent(PsychArgOut, 6)) {
			// Usercode wants valuator info structs:
			for (i = 0; i < indevs->num_classes; i++) if (indevs->classes[i]->type == XIValuatorClass) numIValuators++;
			PsychAllocOutStructArray(6, TRUE, numIValuators, numValuatorStructFieldNames, valuatorInfo, &valuatorStruct);
		}

		for (i = 0; i < indevs->num_classes; i++) {
			// printf("Class %i: Type %i\n", i, (int) indevs->classes[i]->type);
			if (indevs->classes[i]->type == XIButtonClass) {
				// Number of buttons: For all pointers.
				numButtons = ((XIButtonClassInfo*) indevs->classes[i])->num_buttons;

				// Button state for slave pointers. Will get overriden for master pointers:
				buttons_return.mask = ((XIButtonClassInfo*) indevs->classes[i])->state.mask;
				buttons_return.mask_len = ((XIButtonClassInfo*) indevs->classes[i])->state.mask_len;
			}

			// Axis state for slave pointers. First two axis (x,y) will get overriden for master pointers:
			if (indevs->classes[i]->type == XIValuatorClass) {
				XIValuatorClassInfo* axis = (XIValuatorClassInfo*) indevs->classes[i];
				if (axis->number == 0) mxd = axis->value;  // x-Axis.
				if (axis->number == 1) myd = axis->value;  // y-Axis.

				// Additional axis, e.g., digitizer tablet, touchpads etc.:
				if (axis->number >= 0 && axis->number < 100) {
					myvaluators[axis->number] = axis->value;
					numvaluators = (numvaluators >= axis->number + 1) ? numvaluators : axis->number + 1;
				}

				// Assign valuator info struct, if requested:
				if (valuatorStruct) {
					if (axis->label != None) {
						char* atomlabel =  XGetAtomName(dpy, axis->label);
						PsychSetStructArrayStringElement("label", axis->number, atomlabel, valuatorStruct);
						XFree(atomlabel);
					} else {
						PsychSetStructArrayStringElement("label", axis->number, "None", valuatorStruct);
					}

					PsychSetStructArrayDoubleElement("min", axis->number, (double) axis->min, valuatorStruct);
					PsychSetStructArrayDoubleElement("max", axis->number, (double) axis->max, valuatorStruct);
					PsychSetStructArrayDoubleElement("resolution", axis->number, (double) axis->resolution, valuatorStruct);
					PsychSetStructArrayDoubleElement("mode", axis->number, (double) axis->mode, valuatorStruct);
					PsychSetStructArrayDoubleElement("sourceID", axis->number, (double) axis->sourceid, valuatorStruct);
				}
				// printf("AXIS %i, LABEL = %s, MIN = %f, MAX = %f, VAL = %f\n", axis->number, (char*) "NONE", (float) axis->min, (float) axis->max, (float) axis->value);
			}
		}

		// Add 32 buttons for modifier key state vector:
		numButtons += 32;

		// A real master pointer: Use official query for mouse devices.
		if (indevs->use == XIMasterPointer) {
			// Query pointer location and state:
			XIQueryPointer(dpy, indevs->deviceid, RootWindow(dpy, PsychGetXScreenIdForScreen(screenNumber)), &rootwin, &childwin, &mxd, &myd, &dxd, &dyd,
				       &buttons_return, &modifiers_return, &group_return);
		}

		// Copy out mouse x and y position:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, mxd);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, myd);

		// Copy out mouse button state:
		PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int) numButtons, (int)1, &buttonArray);
		memset(buttonArray, 0, sizeof(double) * numButtons);

		if (numButtons > 0) {
			// Mouse buttons:
			const int buttonOffset = 1; // Buttons start at bit 1, not 0 for some strange reason? At least so on Ubuntu 10.10 and 11.10 with 2 mice and 1 joystick?
			for (i = buttonOffset; (i < numButtons - 32) && ((i / 8 ) < buttons_return.mask_len); i++) {
				buttonArray[i - buttonOffset] = (double) ((buttons_return.mask[i / 8] & (1 << (i % 8))) ? 1 : 0);
			}

			// Free mask if retrieved via XIQueryPointer():
			if (indevs->use == XIMasterPointer) free(buttons_return.mask);

			// Append modifier key state from associated master keyboard. Last 32 entries:
			for (i = 0; i < 32; i++) {
				buttonArray[numButtons - 32 + i] = (double) ((modifiers_return.effective & (1 << i)) ? 1 : 0);
			}
		}

		// Release live state info structure:
		XIFreeDeviceInfo(indevs);
	  }
	  else {
		// Old school core protocol query of virtual core pointer:
		XQueryPointer(dpy, RootWindow(dpy, PsychGetXScreenIdForScreen(screenNumber)), &rootwin, &childwin, &mx, &my, &dx, &dy, &mask_return);
	  
		// Copy out mouse x and y position:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) mx);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) my);
	  
		// Copy out mouse button state:
		PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int)numButtons, (int)1, &buttonArray);

		// Bits 8, 9 and 10 of mask_return seem to correspond to mouse buttons
		// 1, 2 and 3 of a mouse for some weird reason. Bits 0-7 describe keyboard modifier keys
		// like Alt, Ctrl, Shift, ScrollLock, NumLock, CapsLock...
		// We remap here, so the first three returned entries correspond to the mouse buttons and
		// the rest is attached behind, if requested...
	  
		// Mouse buttons: Left, Middle, Right == 0, 1, 2, aka 1,2,3 in Matlab space...
		for (i=0; i<numButtons && i<3; i++) {
			buttonArray[i] = (mask_return & (1<<(i+8))) ? 1 : 0; 
		}
		// Modifier keys 0 to 7 appended:
		for (i=3; i<numButtons && i<3+8; i++) {
			buttonArray[i] = (mask_return & (1<<(i-3))) ? 1 : 0; 
		}
		// Everything else appended:
		for (i=11; i<numButtons; i++) {
			buttonArray[i] = (mask_return & (1<<i)) ? 1 : 0; 
		}
	  }

	  // Return optional 4th argument: Focus state. Returns 1 if our window has
	  // keyboard input focus, zero otherwise:
	  XGetInputFocus(dpy, &rootwin, &i);
	  PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) (rootwin == mywin) ? 1 : 0);

	  // Return optional valuator values:
	  PsychCopyOutDoubleMatArg(5, kPsychArgOptional, (int) 1, (int) numvaluators, (int) 1, &myvaluators[0]);
	}
	else {
	  // 'KeyboardHelper' mode: We implement either KbCheck() or KbWait() via X11.
	  // This is a hack to provide keyboard queries until a PsychHID() implementation
	  // for Linux is available...

		// Special codes -10 to -15? --> Console keyboard queries:
		if(numButtons <= -10 && numButtons >= -15) {
			ConsoleInputHelper((int) numButtons);
			return(PsychError_none);
		}
		
	  if (numButtons==-1 || numButtons==-2) {
	    // KbCheck()/KbWait() mode:

	    // Switch X-Server into synchronous mode: We need this to get
	    // a higher timing precision.
	    XSynchronize(dpy, TRUE);

	    do {
	      // Reset overall key state to "none pressed":
	      keysdown=0;

	      // Request current keyboard state from X-Server:
	      XQueryKeymap(dpy, keys_return);

	      // Request current time of query:
	      PsychGetAdjustedPrecisionTimerSeconds(&timestamp);

	      // Any key down?
	      for (i=0; i<32; i++) keysdown+=(unsigned int) keys_return[i];
	      
	      // We repeat until any key pressed if in KbWait() mode, otherwise we
	      // exit the loop after first iteration in KbCheck mode.
	      if ((numButtons==-1) || ((numButtons==-2) && (keysdown>0))) break;

	      // Sleep for a few milliseconds before next KbWait loop iteration:
	      PsychWaitIntervalSeconds(0.01);
	    } while(1);

	    if (numButtons==-2) {
	      // Copy out time:
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, timestamp);
	    }
	    else {
	      // KbCheck mode:
	      
	      // Copy out overall keystate:
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, (keysdown>0) ? 1 : 0);
	      // copy out timestamp:
	      PsychCopyOutDoubleArg(2, kPsychArgOptional, timestamp);	      
	      // Copy keyboard state:
	      PsychAllocOutBooleanMatArg(3, kPsychArgOptional, 1, 256, 1, &buttonStates);

	      // Map 32 times 8 bitvector to 256 element return vector:
	      for(i=0; i<32; i++) {
				for(j=0; j<8; j++) {
		  			buttonStates[i*8 + j] = (PsychNativeBooleanType)(keys_return[i] & (1<<j)) ? 1 : 0;
				}
	      }
	    }
	  }
	  else if (numButtons == -3) {
	    // numButtons == -3 --> KbName mapping mode:
	    // Return the full keyboard keycode to ASCII character code mapping table...
	    PsychAllocOutCellVector(1, kPsychArgOptional, 256, &kbNames);

	    for(i=0; i<256; i++) {
	      // Map keyboard scan code to KeySym:
	      keystring = XKeysymToString(XKeycodeToKeysym(dpy, i, 0));
	      if (keystring) {
		// Character found: Return its ASCII name string:
		PsychSetCellVectorStringElement(i, keystring, kbNames);
	      }
	      else {
		// No character for this keycode:
		PsychSetCellVectorStringElement(i, "", kbNames);
	      }
	    }
	  }
	  else if (numButtons == -4) {
	    // GetChar() emulation.

/* 	    do { */
/* 	      // Fetch next keypress event from queue, block if none is available... */
/* 	      keystring = NULL; */
/* 	      XNextEvent(dpy, &event_return); */
/* 	      // Check for valid keypress event and extract character: */
/* 	      if (event_return.type == KeyPress) { */
/* 		keypressevent = (XKeyPressedEvent) event_return; */
/* 		keystring = NULL; */
/* 		keystring = XKeysymToString(XKeycodeToKeysym(dpy, keypressevent.keycode, 0)); */
/* 	      } */
/* 	      // Repeat until a valid char is returned. */
/* 	    } while (keystring == NULL); */

/* 	    // Copy out character: */
/* 	    PsychCopyOutCharArg(1, kPsychArgOptional, (char) keystring); */
/* 	    // Copy out time: */
/* 	    PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) keypressevent.time); */
	  }
	  else if (numButtons==-5) {
		// Priority() - helper mode: The 2nd argument is the priority level:

		// Query scheduling policy and priority:
		pthread_getschedparam(pthread_self(), &priorityLevel, &schedulingparam);

		// If scheduling mode is a realtime mode (RoundRobin realtime RR, or FIFO realtime),
		// then assign RT priority level (range 1-99) as current priorityLevel, otherwise
		// assign non realtime priority level zero:
		priorityLevel = (priorityLevel == SCHED_RR || priorityLevel == SCHED_FIFO) ? schedulingparam.sched_priority : 0;
        
		// Copy it out as optional return argument:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) priorityLevel);
		
		// Query if a new level should be set:
		priorityLevel = -1;
		PsychCopyInIntegerArg(2, kPsychArgOptional, &priorityLevel);

		errno=0;
		// Priority level provided?
		if (priorityLevel > -1) {
			// Map to new scheduling class:
			if (priorityLevel > 99 || priorityLevel < 0) PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "Invalid Priority level: Requested Priority() level must be between zero and 99!");

			if (priorityLevel > 0) {
				// Realtime FIFO scheduling and all pages of Matlab/Octave locked into memory:
				schedulingparam.sched_priority = priorityLevel;
				priorityLevel = pthread_setschedparam(pthread_self(), SCHED_FIFO, &schedulingparam);
				if (priorityLevel == -1) {
					// Failed!
					if(!PsychPrefStateGet_SuppressAllWarnings()) {
	    					printf("PTB-ERROR: Failed to enable realtime-scheduling with Priority(%i) [%s]!\n", schedulingparam.sched_priority, strerror(errno));
						if (errno==EPERM) {
							printf("PTB-ERROR: You need to run Matlab/Octave with root-privileges, or run the script PsychLinuxConfiguration once for this to work.\n");
						}
					}
					errno=0;
				}
				else {
					// RT-Scheduling active. Lock all current and future memory:
					priorityLevel = mlockall(MCL_CURRENT | MCL_FUTURE);
					if (priorityLevel!=0) {
						// Failed! Report problem as warning, but don't worry further. 
	    					if(!PsychPrefStateGet_SuppressAllWarnings()) printf("PTB-WARNING: Failed to enable system memory locking with Priority(%i) [%s]!\n", schedulingparam.sched_priority, strerror(errno));
						// Undo any possibly partial mlocks....
						munlockall();
						errno=0;
					}
				}
			}
			else {
				// Standard scheduling and no memory locking:
				schedulingparam.sched_priority = 0;
				priorityLevel = pthread_setschedparam(pthread_self(), SCHED_OTHER, &schedulingparam);
				if (priorityLevel == -1) {
					// Failed!
					if(!PsychPrefStateGet_SuppressAllWarnings()) {
	    					printf("PTB-ERROR: Failed to disable realtime-scheduling with Priority(%i) [%s]!\n", schedulingparam.sched_priority, strerror(errno));
						if (errno==EPERM) {
							printf("PTB-ERROR: You need to run Matlab/Octave with root-privileges, or run the script PsychLinuxConfiguration once for this to work.\n");
						}
					}
					errno=0;
				}

				munlockall();
				errno=0;
			}
			// End of setup of new Priority...
		}
		// End of Priority() helper for Linux.
	  }
	}	// End of special functions handling for Linux...
#endif
	return(PsychError_none);	
}
PsychError SCREENPreloadTextures(void)  
{	
	PsychWindowRecordType                   *windowRecord, *texwin;
	psych_bool                                 isArgThere;
        int                                     *texhandles;
        PsychWindowRecordType                   **windowRecordArray;        
        int                                     i, n, numWindows, myhandle; 
        double                                  *success;
        psych_bool*                                residency;
        GLuint*                                 texids;
        GLboolean*                              texresident;
        psych_bool                                 failed = false;
        GLclampf                                maxprio = 1.0f;
        GLenum                                  target;

	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous arguments
	PsychErrorExit(PsychCapNumInputArgs(2));        //The maximum number of inputs
	PsychErrorExit(PsychRequireNumInputArgs(1));    //The minimum number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(2));       //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 optional texids vector:
	isArgThere = PsychIsArgPresent(PsychArgIn, 2);
        PsychAllocInIntegerListArg(2, FALSE, &n, &texhandles);
        if (n < 1) isArgThere=FALSE;
        
        // Enable this windowRecords framebuffer as current drawingtarget:
        PsychSetDrawingTarget(windowRecord);

		// Disable shader:
		PsychSetShader(windowRecord, 0);
	

        glDisable(GL_TEXTURE_2D);

	// Fetch global texturing mode:
	target=PsychGetTextureTarget(windowRecord);

        glEnable(target);
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
        glColor4f(0, 0, 0, 0);
	// Setup identity modelview matrix:
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        glLoadIdentity();

        PsychCreateVolatileWindowRecordPointerList(&numWindows, &windowRecordArray);            

        // Process vector of all texids for all requested textures:
        if (!isArgThere) {
            // No handles provided: In this case, we preload all textures:
            n=0;
            for(i=0; i<numWindows; i++) {                
                if (windowRecordArray[i]->windowType==kPsychTexture) {
                    n++;
                    // Prioritize this texture:
                    glPrioritizeTextures(1, (GLuint*) &(windowRecordArray[i]->textureNumber), &maxprio);
                    // Bind this texture:
                    glBindTexture(target, windowRecordArray[i]->textureNumber);
                    // Render a single textured point, thereby enforcing a texture upload:
                    glBegin(GL_QUADS);
                    glTexCoord2f(0,0); glVertex2i(10,10);
                    glTexCoord2f(0,1); glVertex2i(10,11);
                    glTexCoord2f(1,1); glVertex2i(11,11);
                    glTexCoord2f(1,0); glVertex2i(11,10);                    
                    glEnd();
                }
            }
            
            texids = (GLuint*) PsychMallocTemp(sizeof(GLuint) * n);
            texresident = (GLboolean*) PsychMallocTemp(sizeof(GLboolean) * n);

            n=0;
            for(i=0; i<numWindows; i++) {                
                if (windowRecordArray[i]->windowType==kPsychTexture) {
                    texids[n] = (GLuint) windowRecordArray[i]->textureNumber;
                    n++;
                }
            }
        }
        else {
            // Vector with texture handles provided: Just preload them.
            texids = (GLuint*) PsychMallocTemp(sizeof(GLuint) * n);
            texresident = (GLboolean*) PsychMallocTemp(sizeof(GLboolean) * n);
            myhandle=0;
            for (i=0; i<n; i++) {
                myhandle = texhandles[i];
                texwin = NULL;
                if (IsWindowIndex(myhandle)) FindWindowRecord(myhandle, &texwin);
                if (texwin && texwin->windowType==kPsychTexture) {
                    // Prioritize this texture:
                    glPrioritizeTextures(1, (GLuint*) &(texwin->textureNumber), &maxprio);
                    // Bind this texture:
                    glBindTexture(target, texwin->textureNumber);
                    // Render a single textured point, thereby enforcing a texture upload:
                    glBegin(GL_QUADS);
                    glTexCoord2f(0,0); glVertex2i(10,10);
                    glTexCoord2f(0,1); glVertex2i(10,11);
                    glTexCoord2f(1,1); glVertex2i(11,11);
                    glTexCoord2f(1,0); glVertex2i(11,10);                    
                    glEnd();
                    texids[i] = (GLuint) texwin->textureNumber;
                }
                else {
                    // This handle is invalid or at least no texture handle:
                    printf("PTB-ERROR! Screen('PreloadTextures'): Entry %i of texture handle vector (handle %i) is not a texture handle!\n",
                           i, myhandle);
                    failed = true;
                }
            }
        }
        
        // Restore old matrix from backup copy, undoing the global translation:
        glPopMatrix();
        // Disable texture engine:
        glDisable(GL_TEXTURE_2D);
        glDisable(target);

        // Wait for prefetch completion:
        glFinish();
        
        // We don't need these anymore:
        PsychDestroyVolatileWindowRecordPointerList(windowRecordArray);
        
        if (failed) {
            PsychErrorExitMsg(PsychError_user, "At least one texture handle in texids-vector was invalid! Aborted.");
        }
        
        // Query residency state of all preloaded textures:
        success = NULL;
        PsychAllocOutDoubleArg(1, FALSE, &success);
        *success = (double) glAreTexturesResident(n, texids, texresident);
        
        // Sync pipe again, just to be safe...
        glFinish();
        
        // Count them and copy them into output vector:
        PsychAllocOutBooleanMatArg(2, FALSE, n, 1, 1, &residency);
        
        for (i=0; i<n; i++) {
            residency[i] = (psych_bool) ((*success) ? TRUE : texresident[i]);
        }
        
        PsychTestForGLErrors();
        
 	// Done. Our PsychMallocTemp'ed arrays will be auto-released...
	return(PsychError_none);
}
Esempio n. 22
0
PsychError SCREENPutImage(void) 
{
	PsychRectType 		windowRect,positionRect;
	int 			ix, iy, numPlanes, bitsPerColor, matrixRedIndex, matrixGreenIndex, matrixBlueIndex, matrixAlphaIndex, matrixGrayIndex;
	int 			inputM, inputN, inputP, positionRectWidth, positionRectHeight; 
	PsychWindowRecordType	*windowRecord;
	unsigned char		*inputMatrixByte;
	double			*inputMatrixDouble;
	GLuint			*compactMat, matrixGrayValue, matrixRedValue, matrixGreenValue, matrixBlueValue, matrixAlphaValue, compactPixelValue;
	PsychArgFormatType	inputMatrixType;
	GLfloat			xZoom=1, yZoom=-1;
        
	//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(4));   //The maximum number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(0));  //The maximum number of outputs
        
        //get the image matrix
        inputMatrixType=PsychGetArgType(2);
        switch(inputMatrixType){
            case PsychArgType_none : case PsychArgType_default:
                PsychErrorExitMsg(PsychError_user, "imageArray argument required");
                break;
            case PsychArgType_uint8 :
                PsychAllocInUnsignedByteMatArg(2, TRUE, &inputM, &inputN, &inputP, &inputMatrixByte);
                break;
            case PsychArgType_double :
                PsychAllocInDoubleMatArg(2, TRUE, &inputM, &inputN, &inputP, &inputMatrixDouble);
                break;
            default :
                PsychErrorExitMsg(PsychError_user, "imageArray must be uint8 or double type");
                break;
        }
        
        //get the window and get the rect and stuff
        PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
        numPlanes=PsychGetNumPlanesFromWindowRecord(windowRecord);
        bitsPerColor=PsychGetColorSizeFromWindowRecord(windowRecord);
        PsychGetRectFromWindowRecord(windowRect, windowRecord);
	if(PsychCopyInRectArg(3, FALSE, positionRect)){
            positionRectWidth=(int)PsychGetWidthFromRect(positionRect);
            positionRectHeight=(int)PsychGetHeightFromRect(positionRect);
            if(inputP != 1 && inputP != 3 && inputP != 4)
                PsychErrorExitMsg(PsychError_user, "Third dimension of image matrix must be 1, 3, or 4"); 
            if( positionRectWidth != inputN  || positionRectHeight != inputM){
                //calculate the zoom factor
                xZoom=(GLfloat)positionRectWidth/(GLfloat)inputN;
                yZoom=-((GLfloat)positionRectHeight/(GLfloat)inputM);
            }
        }else{
           positionRect[kPsychLeft]=0;
           positionRect[kPsychTop]=0;
           positionRect[kPsychRight]=inputN;
           positionRect[kPsychBottom]=inputM;
           PsychCenterRect(positionRect, windowRect, positionRect);
           //This should be centered  
        }
        
        
        //put up the image
        if(numPlanes==1){  //screen planes, not image matrix planes.  
            PsychErrorExitMsg(PsychError_unimplemented, "Put Image does not yet support indexed mode");
            //remember to test here for inputP==3 because that would be wrong. 
        }else if(numPlanes==4){
            compactMat=(GLuint *)mxMalloc(sizeof(GLuint) * inputN * inputM);
            for(ix=0;ix<inputN;ix++){
                for(iy=0;iy<inputM;iy++){
                    if(inputP==1){
                        matrixGrayIndex=PsychIndexElementFrom3DArray(inputM, inputN, 1, iy, ix, 0);
                        if(inputMatrixType==PsychArgType_uint8)
                            matrixGrayValue=(GLuint)inputMatrixByte[matrixGrayIndex];
                        else //inputMatrixType==PsychArgType_double
                            matrixGrayValue=(GLuint)inputMatrixDouble[matrixGrayIndex];
                
                        compactPixelValue=((matrixGrayValue<<8 | matrixGrayValue)<<8 | matrixGrayValue)<<8 | 255; 
                        compactMat[iy*inputN+ix]=compactPixelValue; 
                    }else if(inputP==3){
                        matrixRedIndex=PsychIndexElementFrom3DArray(inputM, inputN, 3, iy, ix, 0);
                        matrixGreenIndex=PsychIndexElementFrom3DArray(inputM, inputN, 3, iy, ix, 1);
                        matrixBlueIndex=PsychIndexElementFrom3DArray(inputM, inputN, 3, iy, ix, 2);
                        if(inputMatrixType==PsychArgType_uint8){
                            matrixRedValue=(GLuint)inputMatrixByte[matrixRedIndex];
                            matrixGreenValue=(GLuint)inputMatrixByte[matrixGreenIndex];
                            matrixBlueValue=(GLuint)inputMatrixByte[matrixBlueIndex];
                            matrixAlphaValue=(GLuint)255;
                        }else{
                            matrixRedValue=(GLuint)inputMatrixDouble[matrixRedIndex];
                            matrixGreenValue=(GLuint)inputMatrixDouble[matrixGreenIndex];
                            matrixBlueValue=(GLuint)inputMatrixDouble[matrixBlueIndex];
                            matrixAlphaValue=(GLuint)255;
                        }
                        compactPixelValue= ((matrixRedValue<<8 | matrixGreenValue )<<8 | matrixBlueValue)<<8 | matrixAlphaValue; 
                        compactMat[iy*inputN+ix]=compactPixelValue; 
                    }else if(inputP==4){
                        matrixRedIndex=PsychIndexElementFrom3DArray(inputM, inputN, 3, iy, ix, 0);
                        matrixGreenIndex=PsychIndexElementFrom3DArray(inputM, inputN, 3, iy, ix, 1);
                        matrixBlueIndex=PsychIndexElementFrom3DArray(inputM, inputN, 3, iy, ix, 2);
                        matrixAlphaIndex=PsychIndexElementFrom3DArray(inputM, inputN, 3, iy, ix, 3);
                        if(inputMatrixType==PsychArgType_uint8){  
                            matrixRedValue=(GLuint)inputMatrixByte[matrixRedIndex];
                            matrixGreenValue=(GLuint)inputMatrixByte[matrixGreenIndex];
                            matrixBlueValue=(GLuint)inputMatrixByte[matrixBlueIndex];
                            matrixAlphaValue=(GLuint)inputMatrixByte[matrixAlphaIndex];
                        }else{
                            matrixRedValue=(GLuint)inputMatrixDouble[matrixRedIndex];
                            matrixGreenValue=(GLuint)inputMatrixDouble[matrixGreenIndex];
                            matrixBlueValue=(GLuint)inputMatrixDouble[matrixBlueIndex];
                            matrixAlphaValue=(GLuint)inputMatrixDouble[matrixAlphaIndex];
                        }
                        compactPixelValue= ((matrixRedValue<<8 | matrixGreenValue )<<8 | matrixBlueValue)<<8 | matrixAlphaValue; 
                        compactMat[iy*inputN+ix]=compactPixelValue; 

                    }

                 }
            }

            PsychSetGLContext(windowRecord);
			PsychUpdateAlphaBlendingFactorLazily(windowRecord);

            glRasterPos2i((GLint)(positionRect[kPsychLeft]), (GLint)(positionRect[kPsychTop]));
            PsychTestForGLErrors();
            glPixelStorei(GL_UNPACK_ALIGNMENT, (GLint)(sizeof(GLuint)));  //4  
            PsychTestForGLErrors();
            glPixelZoom(xZoom,yZoom);
            PsychTestForGLErrors();            
            glDrawPixels(inputN, inputM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, compactMat);
            free((void *)compactMat);
            PsychTestForGLErrors();
            PsychFlushGL(windowRecord);  //OS X: This does nothing if we are multi buffered, otherwise it glFlushes
						
			
            PsychTestForGLErrors();
        }else if(numPlanes==3)
            PsychErrorExitMsg(PsychError_unimplemented, "PutImage found hardware without an alpha channel.");	

	return(PsychError_none);
}
PsychError SCREENDrawLines(void)  
{
	PsychWindowRecordType		*windowRecord;
	int							m,n,p, smooth;
	int							nrsize, nrcolors, nrvertices, mc, nc, pc, i;
	boolean                     isArgThere, usecolorvector, isdoublecolors, isuint8colors;
	double						*xy, *size, *center, *dot_type, *colors;
	unsigned char               *bytecolors;
	float						linesizerange[2];
	double						convfactor;

	//all sub functions should have these two lines
	PsychPushHelp(useString, synopsisString,seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//check for superfluous arguments
	PsychErrorExit(PsychCapNumInputArgs(6));   //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);
	
	// Query, allocate and copy in all vectors...
	nrvertices = 2;
	nrsize = 1;

	colors = NULL;
	bytecolors = NULL;

	PsychPrepareRenderBatch(windowRecord, 2, &nrvertices, &xy, 4, &nc, &mc, &colors, &bytecolors, 3, &nrsize, &size);
	isdoublecolors = (colors) ? TRUE:FALSE;
	isuint8colors  = (bytecolors) ? TRUE:FALSE;
	usecolorvector = (nc>1) ? TRUE:FALSE;

	// Get center argument
	isArgThere = PsychIsArgPresent(PsychArgIn, 5);
	if(!isArgThere){
		center = (double *) PsychMallocTemp(2 * sizeof(double));
		center[0] = 0;
		center[1] = 0;
	} else {
		PsychAllocInDoubleMatArg(5, TRUE, &m, &n, &p, &center);
		if(p!=1 || n!=2 || m!=1) PsychErrorExitMsg(PsychError_user, "center must be a 1-by-2 vector");
	}
	
	// Get smooth argument
	isArgThere = PsychIsArgPresent(PsychArgIn, 6);
	if(!isArgThere){
		smooth = 0;
	} else {
		PsychAllocInDoubleMatArg(6, TRUE, &m, &n, &p, &dot_type);
		smooth = (int) dot_type[0];
		if(p!=1 || n!=1 || m!=1 || (smooth!=0 && smooth!=1)) PsychErrorExitMsg(PsychError_user, "smooth must be 0 or 1");
	}

	// Child-protection: Alpha blending needs to be enabled for smoothing to work:
	if (smooth>0 && windowRecord->actualEnableBlending!=TRUE) {
		PsychErrorExitMsg(PsychError_user, "Line smoothing doesn't work with alpha-blending disabled! See Screen('BlendFunction') on how to enable it.");
	}

	// turn on antialiasing to draw anti-aliased lines:
	if(smooth) glEnable(GL_LINE_SMOOTH);

	// Set global width of lines:
	glLineWidth(size[0]);

	// Setup modelview matrix to perform translation by 'center':
	glMatrixMode(GL_MODELVIEW);	
	
	// Make a backup copy of the matrix:
	glPushMatrix();
	
	// Apply a global translation of (center(x,y)) pixels to all following lines:
	glTranslated(center[0], center[1],0);
	
	// Render the array of 2D-Lines - Efficient version:
	// This command sequence allows fast processing of whole arrays
	// of vertices (or lines, in this case). It saves the call overhead
	// associated with the original implementation below and is potentially
	// optimized in specific OpenGL implementations.
	
	// Pass a pointer to the start of the arrays:
	glVertexPointer(2, GL_DOUBLE, 0, &xy[0]);
	
	if (usecolorvector) {
		if (isdoublecolors) glColorPointer(mc, GL_DOUBLE, 0, colors);
		if (isuint8colors)  glColorPointer(mc, GL_UNSIGNED_BYTE, 0, bytecolors);
		glEnableClientState(GL_COLOR_ARRAY);
	}

	// Enable fast rendering of arrays:
	glEnableClientState(GL_VERTEX_ARRAY);

	if (nrsize==1) {
		// Common line-width for all lines: Render all lines, starting at line 0:
		glDrawArrays(GL_LINES, 0, nrvertices);
	}
	else {
		// Different line-width per line: Need to manually loop through this mess:
		for (i=0; i < nrvertices/2; i++) {
	      glLineWidth(size[i]);

	      // Render line:
	      glDrawArrays(GL_LINES, i * 2, 2);
		}
	}
	
	// Disable fast rendering of arrays:
	glDisableClientState(GL_VERTEX_ARRAY);
	if (usecolorvector) glDisableClientState(GL_COLOR_ARRAY);
	
	// Restore old matrix from backup copy, undoing the global translation:
	glPopMatrix();
	
	// Turn off anti-aliasing:
	if(smooth) glDisable(GL_LINE_SMOOTH);
	
	// Reset line width to 1.0:
	glLineWidth(1);
	
	// Mark end of drawing op. This is needed for single buffered drawing:
	PsychFlushGL(windowRecord);
	
 	//All psychfunctions require this.
	return(PsychError_none);
}
PsychError SCREENLineStipple(void)  
{
	
	PsychWindowRecordType			*winRec;
	static GLushort					stipplePatternTemp;
	boolean							isFactorThere, isPatternThere, isFlagThere, didChange;
	double							*newFactor;
	boolean							*newPatternArray;
	int								numInputVectorElements;
	PsychNativeBooleanType			*oldPatternArray;
	boolean							*newEnableFlag;
								
    
	//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(3));  //The maximum number of outputs

	//get the window record from the window record argument and get info from the window record
	PsychAllocInWindowRecordArg(1, kPsychArgRequired, &winRec);
	
	//return existing values
	PsychCopyOutFlagArg(1, kPsychArgOptional, winRec->stippleEnabled);
	PsychCopyOutDoubleArg(2,  kPsychArgOptional, (double)winRec->stippleFactor); 
	PsychAllocOutBooleanMatArg(3, kPsychArgOptional, 1, 16, 0, &oldPatternArray);
	ConvertShortToStippleArray(oldPatternArray, winRec->stipplePattern);
	
	//read in new values
	didChange=FALSE;
	isFlagThere=PsychAllocInFlagArg(2, kPsychArgOptional, &newEnableFlag);
	if(isFlagThere && *newEnableFlag != winRec->stippleEnabled){
		didChange=TRUE;
		winRec->stippleEnabled=*newEnableFlag;
	}
	
	isFactorThere=PsychAllocInDoubleArg(3, kPsychArgOptional, &newFactor);
	if(isFactorThere && (GLint)(*newFactor) != winRec->stippleFactor){
		didChange=TRUE;
		winRec->stippleFactor=(GLint)(*newFactor);
	}
	
	//NOTE: fix PsychAllocInFlagArgVector so that it limits to numInputVectorElements.  
	isPatternThere=PsychAllocInFlagArgVector(4, kPsychArgOptional, &numInputVectorElements, &newPatternArray);
	if(isPatternThere){
		if(numInputVectorElements != 16)
			PsychErrorExitMsg(PsychError_inputMatrixIllegalDimensionSize, "Argument \"stipplePattern\" should be a vector of 16 elements in size");
		ConvertStippleArrayToShort(newPatternArray, &stipplePatternTemp);
		if(stipplePatternTemp != winRec->stipplePattern){
			didChange=TRUE;
			winRec->stipplePattern=stipplePatternTemp;
		}
	}
	
	//Update GL context according to new settings. 
	if(didChange){   //avoids unnecessary context switches
		PsychSetGLContext(winRec);
		glLineStipple(winRec->stippleFactor, winRec->stipplePattern);
		if(winRec->stippleEnabled)
			glEnable(GL_LINE_STIPPLE);
		else
			glDisable(GL_LINE_STIPPLE);
	}
   
 	//All psychfunctions require this.
	return(PsychError_none);
}
Esempio n. 25
0
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 SCREENGetWindowInfo(void) 
{
    const char *FieldNames[]={ "Beamposition", "LastVBLTimeOfFlip", "LastVBLTime", "VBLCount", "TimeAtSwapRequest", "TimePostSwapRequest", "RawSwapTimeOfFlip",
							   "VBLTimePostFlip", "OSSwapTimestamp", "GPULastFrameRenderTime", "StereoMode", "ImagingMode", "MultiSampling", "MissedDeadlines", "FlipCount", "StereoDrawBuffer",
							   "GuesstimatedMemoryUsageMB", "VBLStartline", "VBLEndline", "VideoRefreshFromBeamposition", "GLVendor", "GLRenderer", "GLVersion", "GPUCoreId", 
							   "GLSupportsFBOUpToBpc", "GLSupportsBlendingUpToBpc", "GLSupportsTexturesUpToBpc", "GLSupportsFilteringUpToBpc", "GLSupportsPrecisionColors",
							   "GLSupportsFP32Shading", "BitsPerColorComponent", "IsFullscreen", "SpecialFlags", "SwapGroup", "SwapBarrier" };
							   
	const int  fieldCount = 35;
	PsychGenericScriptType	*s;

    PsychWindowRecordType *windowRecord;
    double beamposition, lastvbl;
	int infoType = 0, retIntArg;
	double auxArg1, auxArg2, auxArg3;
	CGDirectDisplayID displayId;
	psych_uint64 postflip_vblcount;
	double vbl_startline;
	long scw, sch;
	psych_bool onscreen;
    
    //all subfunctions should have these two lines.  
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    PsychErrorExit(PsychCapNumInputArgs(5));     //The maximum number of inputs
    PsychErrorExit(PsychRequireNumInputArgs(1)); //The required number of inputs	
    PsychErrorExit(PsychCapNumOutputArgs(1));    //The maximum number of outputs

    // Query infoType flag: Defaults to zero.
    PsychCopyInIntegerArg(2, FALSE, &infoType);
	if (infoType < 0 || infoType > 5) PsychErrorExitMsg(PsychError_user, "Invalid 'infoType' argument specified! Valid are 0, 1, 2, 3, 4 and 5.");

	// Windowserver info requested?
	if (infoType == 2 || infoType == 3) {
		// Return info about WindowServer:
		#if PSYCH_SYSTEM == PSYCH_OSX

		const char *CoreGraphicsFieldNames[]={ "CGSFps", "CGSValue1", "CGSValue2", "CGSValue3", "CGSDebugOptions" };
		const int CoreGraphicsFieldCount = 5;
		float cgsFPS, val1, val2, val3;
		
		// This (undocumented) Apple call retrieves information about performance statistics of
		// the Core graphics server, also known as WindowServer or Quartz compositor:
		CGSGetPerformanceData(_CGSDefaultConnection(), &cgsFPS, &val1, &val2, &val3);
		if (CGSGetDebugOptions(&retIntArg)) {
			if (PsychPrefStateGet_Verbosity() > 1) printf("PTB-WARNING: GetWindowInfo: Call to CGSGetDebugOptions() failed!\n");
		}
		
		PsychAllocOutStructArray(1, FALSE, 1, CoreGraphicsFieldCount, CoreGraphicsFieldNames, &s);
		PsychSetStructArrayDoubleElement("CGSFps", 0   , cgsFPS, s);
		PsychSetStructArrayDoubleElement("CGSValue1", 0, val1, s);
		PsychSetStructArrayDoubleElement("CGSValue2", 0, val2, s);
		PsychSetStructArrayDoubleElement("CGSValue3", 0, val3, s);
		PsychSetStructArrayDoubleElement("CGSDebugOptions", 0, (double) retIntArg, s);
		
		if ( (infoType == 3) && PsychCopyInDoubleArg(3, FALSE, &auxArg1) ) {
			// Type 3 setup request with auxArg1 provided. Apple auxArg1 as debugFlag setting
			// for the CoreGraphics server: DANGEROUS!
			if (CGSSetDebugOptions((unsigned int) auxArg1)) {
				if (PsychPrefStateGet_Verbosity() > 1) printf("PTB-WARNING: GetWindowInfo: Call to CGSSetDebugOptions() failed!\n");
			}
		}

		#endif
		
		#if PSYCH_SYSTEM == PSYCH_WINDOWS
		psych_uint64 onsetVBLCount, frameId;
		double onsetVBLTime, compositionRate;
		psych_uint64 targetVBL;
		
		PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
		// Query all DWM presentation timing info, return full info as struct in optional return argument '1':
		if (PsychOSGetPresentationTimingInfo(windowRecord, TRUE, 0, &onsetVBLCount, &onsetVBLTime, &frameId, &compositionRate, 1)) {
			// Query success: Info struct has been created and returned by PsychOSGetPresentationTimingInfo()...
			auxArg1 = auxArg2 = 0;
			auxArg3 = 2;
			
			// Want us to change settings?
			if ( (infoType == 3) && PsychCopyInDoubleArg(3, FALSE, &auxArg1) && PsychCopyInDoubleArg(4, FALSE, &auxArg2) && PsychCopyInDoubleArg(5, FALSE, &auxArg3)) {
				if (auxArg1 < 0) auxArg1 = 0;
				targetVBL = auxArg1;
				if (PsychOSSetPresentParameters(windowRecord, targetVBL, (int) auxArg3, auxArg2)) {
					if (PsychPrefStateGet_Verbosity() > 5) printf("PTB-DEBUG: GetWindowInfo: Call to PsychOSSetPresentParameters(%i, %i, %f) SUCCESS!\n", (int) auxArg1, (int) auxArg3, auxArg2);
				}
				else {
					if (PsychPrefStateGet_Verbosity() > 1) printf("PTB-WARNING: GetWindowInfo: Call to PsychOSSetPresentParameters() failed!\n");
				}
			}
		}
		else {
			// Unsupported / Failed:
			PsychCopyOutDoubleArg(1, FALSE, -1);
		}

		#endif

		#if PSYCH_SYSTEM == PSYCH_LINUX
			if (infoType == 2) {
				// MMIO register Read for screenid "auxArg1", register offset "auxArg2":
				PsychCopyInDoubleArg(3, TRUE, &auxArg1);
				PsychCopyInDoubleArg(4, TRUE, &auxArg2);
				PsychCopyOutDoubleArg(1, FALSE, (double) PsychOSKDReadRegister((int) auxArg1, (unsigned int) auxArg2, NULL));
			}
			
			if (infoType == 3) {
				// MMIO register Write for screenid "auxArg1", register offset "auxArg2", to value "auxArg3":
				PsychCopyInDoubleArg(3, TRUE, &auxArg1);
				PsychCopyInDoubleArg(4, TRUE, &auxArg2);
				PsychCopyInDoubleArg(5, TRUE, &auxArg3);
				PsychOSKDWriteRegister((int) auxArg1, (unsigned int) auxArg2, (unsigned int) auxArg3, NULL);
			}
		#endif

		// Done.
		return(PsychError_none);
	}

    // Get the window record:
    PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
	onscreen = PsychIsOnscreenWindow(windowRecord);

	if (onscreen) {
		// Query rasterbeam position: Will return -1 if unsupported.
		PsychGetCGDisplayIDFromScreenNumber(&displayId, windowRecord->screenNumber);
		beamposition = (double) PsychGetDisplayBeamPosition(displayId, windowRecord->screenNumber);
	}
	else {
		beamposition = -1;
	}
	
	if (infoType == 1) {
		// Return the measured beamposition:
		PsychCopyOutDoubleArg(1, FALSE, beamposition);
	}
    else if (infoType == 4) {
        // Return async flip state: 1 = Active, 0 = Inactive.
        PsychCopyOutDoubleArg(1, FALSE, (((NULL != windowRecord->flipInfo) && (0 != windowRecord->flipInfo->asyncstate)) ? 1 : 0));
    }
	else if (infoType == 5) {
		// Create a GL_EXT_timer_query object for this window:
		if (glewIsSupported("GL_EXT_timer_query")) {
			// Pending queries finished?
			if (windowRecord->gpuRenderTimeQuery > 0) {
				PsychErrorExitMsg(PsychError_user, "Tried to create a new GPU rendertime query, but last query not yet finished! Call Screen('Flip') first!");
			}
			
			// Enable our rendering context by selecting this window as drawing target:
			PsychSetDrawingTarget(windowRecord);
			
			// Generate Query object:
			glGenQueries(1, &windowRecord->gpuRenderTimeQuery);
			
			// Emit Query: GPU will measure elapsed processing time in Nanoseconds, starting
			// with the first GL command executed after this command:
			glBeginQuery(GL_TIME_ELAPSED_EXT, windowRecord->gpuRenderTimeQuery);
			
			// Reset last measurement:
			windowRecord->gpuRenderTime = 0;
		}
		else {
			if (PsychPrefStateGet_Verbosity() > 4) printf("PTB-INFO: GetWindowInfo for infoType 5: GPU timer query objects are unsupported on this platform and GPU. Call ignored!\n");
		}
	}
	else {
		// Return all information:
		PsychAllocOutStructArray(1, FALSE, 1, fieldCount, FieldNames, &s);

		// Rasterbeam position:
		PsychSetStructArrayDoubleElement("Beamposition", 0, beamposition, s);

		// Time of last vertical blank when a double-buffer swap occured:
		if ((windowRecord->flipCount > 0) && (windowRecord->time_at_last_vbl == 0) && (PsychPrefStateGet_VBLTimestampingMode() == 4)) {
			// If time_at_last_vbl for an already finished or at least pending flip isn't available and
			// we have support for OS-Builtin timestamping enabled, we try to employ OS-Builtin timestamping
			// to get a timestamp for the most recent pending or finished flip. If this fails or is unsupported,
			// it will have no effect:
			PsychOSGetSwapCompletionTimestamp(windowRecord, 0, &(windowRecord->time_at_last_vbl));
		}

		// Return it - or the value zero if it is (still) undefined/unavailable:
		PsychSetStructArrayDoubleElement("LastVBLTimeOfFlip", 0, windowRecord->time_at_last_vbl, s);

		// Uncorrected timestamp of flip swap completion:
		PsychSetStructArrayDoubleElement("RawSwapTimeOfFlip", 0, windowRecord->rawtime_at_swapcompletion, s);

		// Timestamp immediately prior to call to PsychOSFlipWindowBuffers(), i.e., time at swap request submission:
		PsychSetStructArrayDoubleElement("TimeAtSwapRequest", 0, windowRecord->time_at_swaprequest, s);

		// Timestamp immediately after call to PsychOSFlipWindowBuffers() returns, i.e., time at swap request submission completion:
		PsychSetStructArrayDoubleElement("TimePostSwapRequest", 0, windowRecord->time_post_swaprequest, s);

		// Timestamp immediately after call to PsychOSFlipWindowBuffers() returns, i.e., time at swap request submission completion:
		PsychSetStructArrayDoubleElement("VBLTimePostFlip", 0, windowRecord->postflip_vbltimestamp, s);

		// Swap completion timestamp for most recently completed swap, according to OS-builtin PsychOSGetSwapCompletionTimestamp() method:
		PsychSetStructArrayDoubleElement("OSSwapTimestamp", 0, windowRecord->osbuiltin_swaptime, s);

		// Result from last GPU rendertime query as triggered by infoType 5: Zero if undefined.
		PsychSetStructArrayDoubleElement("GPULastFrameRenderTime", 0, windowRecord->gpuRenderTime, s);

		// Try to determine system time of last VBL on display, independent of any
		// flips / bufferswaps.
		lastvbl = -1;
		postflip_vblcount = 0;
		
		// On supported systems, we can query the OS for the system time of last VBL, so we can
		// use the most recent VBL timestamp as baseline for timing calculations, 
		// instead of one far in the past.
		if (onscreen) { lastvbl = PsychOSGetVBLTimeAndCount(windowRecord, &postflip_vblcount); }

		// If we couldn't determine this information we just set lastvbl to the last known
		// vbl timestamp of last flip -- better than nothing...
		if (lastvbl < 0) lastvbl = windowRecord->time_at_last_vbl;
		PsychSetStructArrayDoubleElement("LastVBLTime", 0, lastvbl, s);
		PsychSetStructArrayDoubleElement("VBLCount", 0, (double) (psych_int64) postflip_vblcount, s);
        
		// Misc. window parameters:
		PsychSetStructArrayDoubleElement("StereoMode", 0, windowRecord->stereomode, s);
		PsychSetStructArrayDoubleElement("ImagingMode", 0, windowRecord->imagingMode, s);
		PsychSetStructArrayDoubleElement("SpecialFlags", 0, windowRecord->specialflags, s);
		PsychSetStructArrayDoubleElement("IsFullscreen", 0, (windowRecord->specialflags & kPsychIsFullscreenWindow) ? 1 : 0, s);
		PsychSetStructArrayDoubleElement("MultiSampling", 0, windowRecord->multiSample, s);
		PsychSetStructArrayDoubleElement("MissedDeadlines", 0, windowRecord->nr_missed_deadlines, s);
		PsychSetStructArrayDoubleElement("FlipCount", 0, windowRecord->flipCount, s);
		PsychSetStructArrayDoubleElement("StereoDrawBuffer", 0, windowRecord->stereodrawbuffer, s);
		PsychSetStructArrayDoubleElement("GuesstimatedMemoryUsageMB", 0, (double) windowRecord->surfaceSizeBytes / 1024 / 1024, s);
		PsychSetStructArrayDoubleElement("BitsPerColorComponent", 0, (double) windowRecord->bpc, s);
		
		// Query real size of the underlying display in order to define the vbl_startline:
		PsychGetScreenSize(windowRecord->screenNumber, &scw, &sch);
		vbl_startline = (double) sch;
		PsychSetStructArrayDoubleElement("VBLStartline", 0, vbl_startline, s);

		// And VBL endline:
		PsychSetStructArrayDoubleElement("VBLEndline", 0, windowRecord->VBL_Endline, s);

		// Video refresh interval duration from beamposition method:
		PsychSetStructArrayDoubleElement("VideoRefreshFromBeamposition", 0, windowRecord->ifi_beamestimate, s);
    
		// Swap group assignment and swap barrier assignment, if any:
		PsychSetStructArrayDoubleElement("SwapGroup", 0, windowRecord->swapGroup, s);
		PsychSetStructArrayDoubleElement("SwapBarrier", 0, windowRecord->swapBarrier, s);
	
        // Which basic GPU architecture is this?
		PsychSetStructArrayStringElement("GPUCoreId", 0, windowRecord->gpuCoreId, s);
		
		// FBO's supported, and how deep?
		if (windowRecord->gfxcaps & kPsychGfxCapFBO) {
			if (windowRecord->gfxcaps & kPsychGfxCapFPFBO32) {
				PsychSetStructArrayDoubleElement("GLSupportsFBOUpToBpc", 0, 32, s);
			} else
			if (windowRecord->gfxcaps & kPsychGfxCapFPFBO16) {
				PsychSetStructArrayDoubleElement("GLSupportsFBOUpToBpc", 0, 16, s);
			} else PsychSetStructArrayDoubleElement("GLSupportsFBOUpToBpc", 0, 8, s);
		}
		else {
			PsychSetStructArrayDoubleElement("GLSupportsFBOUpToBpc", 0, 0, s);
		}

		// How deep is alpha blending supported?
		if (windowRecord->gfxcaps & kPsychGfxCapFPBlend32) {
			PsychSetStructArrayDoubleElement("GLSupportsBlendingUpToBpc", 0, 32, s);
		} else if (windowRecord->gfxcaps & kPsychGfxCapFPBlend16) {
			PsychSetStructArrayDoubleElement("GLSupportsBlendingUpToBpc", 0, 16, s);
		} else PsychSetStructArrayDoubleElement("GLSupportsBlendingUpToBpc", 0, 8, s);
		
		// How deep is texture mapping supported?
		if (windowRecord->gfxcaps & kPsychGfxCapFPTex32) {
			PsychSetStructArrayDoubleElement("GLSupportsTexturesUpToBpc", 0, 32, s);
		} else if (windowRecord->gfxcaps & kPsychGfxCapFPTex16) {
			PsychSetStructArrayDoubleElement("GLSupportsTexturesUpToBpc", 0, 16, s);
		} else PsychSetStructArrayDoubleElement("GLSupportsTexturesUpToBpc", 0, 8, s);
		
		// How deep is texture filtering supported?
		if (windowRecord->gfxcaps & kPsychGfxCapFPFilter32) {
			PsychSetStructArrayDoubleElement("GLSupportsFilteringUpToBpc", 0, 32, s);
		} else if (windowRecord->gfxcaps & kPsychGfxCapFPFilter16) {
			PsychSetStructArrayDoubleElement("GLSupportsFilteringUpToBpc", 0, 16, s);
		} else PsychSetStructArrayDoubleElement("GLSupportsFilteringUpToBpc", 0, 8, s);

		if (windowRecord->gfxcaps & kPsychGfxCapVCGood) {
			PsychSetStructArrayDoubleElement("GLSupportsPrecisionColors", 0, 1, s);
		} else PsychSetStructArrayDoubleElement("GLSupportsPrecisionColors", 0, 0, s);

		if (windowRecord->gfxcaps & kPsychGfxCapFP32Shading) {
			PsychSetStructArrayDoubleElement("GLSupportsFP32Shading", 0, 1, s);
		} else PsychSetStructArrayDoubleElement("GLSupportsFP32Shading", 0, 0, s);

		// Renderer information: This comes last, and would fail if async flips
        // are active, because it needs PsychSetDrawingTarget, which in turn needs async
        // flips to be inactive:
        PsychSetDrawingTarget(windowRecord);
        PsychSetStructArrayStringElement("GLVendor", 0, (char*) glGetString(GL_VENDOR), s);
        PsychSetStructArrayStringElement("GLRenderer", 0, (char*) glGetString(GL_RENDERER), s);
        PsychSetStructArrayStringElement("GLVersion", 0, (char*) glGetString(GL_VERSION), s);
    }
    
    // Done.
    return(PsychError_none);
}
PsychError SCREENOpenMovie(void)
{
    PsychWindowRecordType                   *windowRecord;
    char                                    *moviefile;
    char                                    *movieOptions;
    char                                    dummmyOptions[1];
    int                                     moviehandle = -1;
    int                                     framecount;
    double                                  durationsecs;
    double                                  framerate;
    double                                  aspectRatio;
    int                                     width;
    int                                     height;
    int                                     asyncFlag = 0;
    int                                     specialFlags1 = 0;
    static psych_bool                       firstTime = TRUE;
    double                                  preloadSecs = 1;
    int                                     rc;
    int                                     pixelFormat = 4;
    int                                     maxNumberThreads = -1;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                asyncmovieinfo.moviehandle = -1;

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

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

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

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

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

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

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

                free(asyncmovieinfo.moviename);

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

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

    // Retrieve infos about new movie:

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

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

    // Ready!
    return(PsychError_none);
}
Esempio n. 28
0
PsychError SCREENFrameOval(void)  
{
	PsychRectType			rect;
	double					numSlices, outerRadius, xScale, yScale, xTranslate, yTranslate, rectY, rectX, penWidth, penHeight, penSize, innerRadius;
	PsychWindowRecordType	*windowRecord;
	psych_bool				isArgThere, isclassic;
    double					*xy, *colors;
	unsigned char			*bytecolors;
	double*					penSizes;
	int						numRects, i, nc, mc, nrsize;
	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(6));   //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);

	// Query, allocate and copy in all vectors...
	numRects = 4;
	nrsize = 0;
	colors = NULL;
	bytecolors = NULL;
	mc = nc = 0;
	
	// The negative position -3 means: xy coords are expected at position 3, but they are optional.
	// NULL means - don't want a size's vector.
	PsychPrepareRenderBatch(windowRecord, -3, &numRects, &xy, 2, &nc, &mc, &colors, &bytecolors, 4, &nrsize, &penSizes, FALSE);
    isclassic = PsychIsGLClassic(windowRecord);

	// Only up to one rect provided?
	if (numRects <= 1) {
		// Get the oval and draw it:
		PsychCopyRect(rect, windowRecord->clientrect);
		isArgThere=PsychCopyInRectArg(kPsychUseDefaultArgPosition, FALSE, rect);	
		if (isArgThere && IsPsychRectEmpty(rect)) return(PsychError_none);
		numRects = 1;

		// Get the pen width and height arguments
		penWidth=1;
		penHeight=1;
		PsychCopyInDoubleArg(4, FALSE, &penWidth);
		PsychCopyInDoubleArg(5, FALSE, &penHeight);
		penSize = (penWidth > penHeight) ? penWidth : penHeight;
	}
	else {
		// Multiple ovals provided. Set up the first one:
        PsychCopyRect(rect, &xy[0]);
		penSize = penSizes[0];
	}

	// Create quadric object:
	if (isclassic) diskQuadric = gluNewQuadric();

	// Draw all ovals (one or multiple):
	for (i=0; i < numRects;) {
		// Per oval color provided? If so then set it up. If only one common color
		// was provided then PsychPrepareRenderBatch() has already set it up.
		if (nc>1) {
			// Yes. Set color for this specific item:
			PsychSetArrayColor(windowRecord, i, mc, colors, bytecolors);
		}

		// Per oval penSize provided? If so, set it up. Otherwise keep at default size
		// common for all ovals, set by code outside loop:
		if (nrsize > 1) penSize = penSizes[i];

		// Compute drawing parameters for ellipse:
		if (!IsPsychRectEmpty(rect)) {
			//The glu disk object location and size with a  center point and a radius,   
			//whereas FrameOval accepts a bounding rect. Converting from one set of parameters
			//to the other we should careful what we do for rects size of even number of pixels in length.
			PsychGetCenterFromRectAbsolute(rect, &xTranslate, &yTranslate);
			rectY=PsychGetHeightFromRect(rect);
			rectX=PsychGetWidthFromRect(rect);
			if(rectX == rectY){
				xScale=1; 
				yScale=1;
				outerRadius=rectX/2;
			}else if(rectX > rectY){ 
				xScale=1;
				yScale=rectY/rectX;
				outerRadius=rectX/2;
			}else {
				yScale=1;
				xScale=rectX/rectY;
				outerRadius=rectY/2;
			}
			
			numSlices   =   3.14159265358979323846  * 2 * outerRadius;
			innerRadius = outerRadius - penSize;
			innerRadius = (innerRadius < 0) ? 0 : innerRadius;         

            if (isclassic) {
                // Draw: Set up position, scale and size via matrix transform:
                glPushMatrix();
                glTranslated(xTranslate, yTranslate, 0);
                glScaled(xScale, yScale, 1);

                // Compute disk quadric for given params: This is awfully slow and would
                // benefit a lot from shader magic on modern GPUs:
                gluDisk(diskQuadric, innerRadius, outerRadius, (int) numSlices, 1);
                glPopMatrix();
            }
            else {
                PsychDrawDisc(windowRecord, (float) xTranslate, (float) yTranslate, (float) innerRadius, (float) outerRadius, (int) numSlices, (float) xScale, (float) yScale, 0, 360);
            }
		}
		
		// Done with this one. Set up the next one, if any...
		i++;
		if (i < numRects) {
            PsychCopyRect(rect, &xy[i*4]);
        }

		// Next oval.
	}

	// Release quadric object:
	if (isclassic) gluDeleteQuadric(diskQuadric);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return(PsychError_none);
}
PsychError 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);
}