Beispiel #1
0
void PsychGLVertex4f(PsychWindowRecordType *windowRecord, float x, float y, float z, float w)
{
    // Classic OpenGL? Use glEnd() and be done:
    if (PsychIsGLClassic(windowRecord)) {
        glVertex4f(x,y,z,w);
        return;
    }

    // Make sure we don't overflow our internal static vertex array bufer:
    if (gl_buffer_index > PSYCH_MAX_IMMSIM_VERTEX_COMPONENTS - 12) {
        printf("PTB-ERROR: Overflow of internal immediate mode rendering buffer! Limit of %i components reached.\n", PSYCH_MAX_IMMSIM_VERTEX_COMPONENTS);
        printf("PTB-ERROR: You must reduce the workload, or your stimulus image will be damaged. Likely culprit is Screen('Fill/FrameOval') with too high level of detail!\n\n");
        return;
    }

    // Store (x,y,z,w) vertex pos first:
    gl_buffer[gl_buffer_index++] = x;
    gl_buffer[gl_buffer_index++] = y;
    gl_buffer[gl_buffer_index++] = z;
    gl_buffer[gl_buffer_index++] = w;

    // Then current color (r,g,b,a):
    gl_buffer[gl_buffer_index++] = (float) currentColor[0];
    gl_buffer[gl_buffer_index++] = (float) currentColor[1];
    gl_buffer[gl_buffer_index++] = (float) currentColor[2];
    gl_buffer[gl_buffer_index++] = (float) currentColor[3];
    
    // Then current texture coordinates (s,t,u,v):
    gl_buffer[gl_buffer_index++] = currentTexCoord[0];
    gl_buffer[gl_buffer_index++] = currentTexCoord[1];
    gl_buffer[gl_buffer_index++] = currentTexCoord[2];
    gl_buffer[gl_buffer_index++] = currentTexCoord[3];

    return;
}
Beispiel #2
0
/*
    PsychSetGLColor()
    
    Accept a Psych color structure and a depth value and call the appropriate variant of glColor.       
*/
void PsychSetGLColor(PsychColorType *color, PsychWindowRecordType *windowRecord)
{
    int numVals;
    
    numVals=PsychConvertColorToDoubleVector(color, windowRecord, (GLdouble*) &(windowRecord->currentColor));
    if(numVals < 3 || numVals > 4) PsychErrorExitMsg(PsychError_internal, "Palette mode not yet implemented or illegal color specifier.");

	// Set the color in GL:
	if (windowRecord->defaultDrawShader) {
		// Drawshader color submission:
		HDRglColor4dv(windowRecord->currentColor);
	}
	else {
		// Fixed function pipe:
        if (PsychIsGLClassic(windowRecord)) {
            // OpenGL-1/2:
            glColor4dv(windowRecord->currentColor);
        }
        else {
            // OpenGL-ES 1.x: glColor4f() is only available function.
            glColor4f((float) windowRecord->currentColor[0], (float) windowRecord->currentColor[1], (float) windowRecord->currentColor[2], (float) windowRecord->currentColor[3]);
            PsychGLColor4f(windowRecord, (float) windowRecord->currentColor[0], (float) windowRecord->currentColor[1], (float) windowRecord->currentColor[2], (float) windowRecord->currentColor[3]);
        }
	}
}
Beispiel #3
0
void PsychGLEnd(PsychWindowRecordType *windowRecord)
{
    // Classic OpenGL? Use glEnd() and be done:
    if (PsychIsGLClassic(windowRecord)) {
        glEnd();
        return;
    }

    // OpenGL 3+ or OpenGL-ES. Need to emulate immediate mode stuff:

    // Work to do?
    if (gl_buffer_index > 0) {
        // Yes: Submit draw call:
        glVertexPointer(4, GL_FLOAT, 4 * 3 * sizeof(float), &gl_buffer[0 * 4]);
        glColorPointer(4,  GL_FLOAT, 4 * 3 * sizeof(float), &gl_buffer[1 * 4]);
        glTexCoordPointer(4,  GL_FLOAT, 4 * 3 * sizeof(float), &gl_buffer[2 * 4]);

        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_COLOR_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);

        glDrawArrays(gl_buffer_primitivetype, 0, gl_buffer_index / (4 * 3));

        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_COLOR_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    }

    // Reset primitive for this Begin->End block:
    gl_buffer_primitivetype = (GLenum) 0xffff;
    gl_buffer_index = 0;

    return;
}
Beispiel #4
0
/* Emit a single pixel in top-left corner of window and wait for its rendering
 * to complete. Our classic trick to wait for double-buffer swap completion on
 * systems where we don't have better system-provided timestamping and syncing
 * methods. This needs different implementations on classic OpenGL vs. non-
 * immediate mode OpenGL.
 *
 * A 'flushOnly' flag of TRUE will only flush, not wait.
 *
 */
void PsychWaitPixelSyncToken(PsychWindowRecordType *windowRecord, psych_bool flushOnly)
{
    // Classic desktop OpenGL in use?
    if (PsychIsGLClassic(windowRecord)) {
        // Yes. Use our classic fixed-function immediate mode method:
        glBegin(GL_POINTS);
        glColor4f(0, 0, 0, 0);
        glVertex2i(10, 10);
        glEnd();
    }
    else {
        // No. Avoid immediate mode functions, they won't work:
        GLfloat glverts[2] = { 10, 10 };
        glVertexPointer(2, GL_FLOAT, 0, glverts);
        glEnableClientState(GL_VERTEX_ARRAY);
        glDrawArrays(GL_POINTS, 0, 1);
        glDisableClientState(GL_VERTEX_ARRAY);
    }

    // flushOnly flag - Don't wait for write to happen, just flush it:
    if (!flushOnly) {
        // Wait for write completion - Used for sync and timestamping:
        glFinish();
    }
    else {
        // Only flush:
        glFlush();
    }

    if (flushOnly && (PsychPrefStateGet_Verbosity() > 15)) printf("PTB-DEBUG: PixelSyncToken write + glFlush().\n");
}
Beispiel #5
0
void PsychGLTexCoord4f(PsychWindowRecordType *windowRecord, float s, float t, float u, float v)
{
    // Classic OpenGL? Use glEnd() and be done:
    if (PsychIsGLClassic(windowRecord)) {
        glTexCoord4f(s, t, u, v);
        return;
    }

    currentTexCoord[0] = s;
    currentTexCoord[1] = t;
    currentTexCoord[2] = u;
    currentTexCoord[3] = v;
}
Beispiel #6
0
void PsychGLRectd(PsychWindowRecordType *windowRecord, double x1, double y1, double x2, double y2)
{
    // Classic OpenGL? Use glRectd() and be done:
    if (PsychIsGLClassic(windowRecord)) {
        glRectd(x1, y1, x2, y2);
        return;
    }

    // Want to emulate a GL_QUAD draw: We do it as a triangle strip:
    GLBEGIN(GL_TRIANGLE_STRIP);
    GLVERTEX2d(x1, y1);
    GLVERTEX2d(x2, y1);
    GLVERTEX2d(x1, y2);
    GLVERTEX2d(x2, y2);
    GLEND();
}
Beispiel #7
0
void PsychGLBegin(PsychWindowRecordType *windowRecord, GLenum primitive)
{
    // Classic OpenGL? Use glBegin() and be done:
    if (PsychIsGLClassic(windowRecord)) {
        glBegin(primitive);
        return;
    }

    // OpenGL 3+ or OpenGL-ES. Need to emulate immediate mode stuff:
    if (gl_buffer_index > 0) PsychErrorExitMsg(PsychError_internal, "PsychGLBegin() called while already inside PsychGLBegin() block!");

    // Assign primitive for this Begin->End block:
    gl_buffer_primitivetype = primitive;

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

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

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

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

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

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

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

	return(PsychError_none);
}
PsychError SCREENFillOval(void)  
{	
	PsychRectType			rect;
	double					numSlices, radius, xScale, yScale, xTranslate, yTranslate, rectY, rectX;
	PsychWindowRecordType	*windowRecord;
	psych_bool				isArgThere, isclassic;
    double					*xy, *colors;
	unsigned char			*bytecolors;
	int						numRects, i, nc, mc, nrsize;
	GLUquadricObj			*diskQuadric;
	double					perfectUpToMaxDiameter;
	static double			perfectUpToMaxDiameterOld = 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(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(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
    isclassic = PsychIsGLClassic(windowRecord);

	perfectUpToMaxDiameter = PsychGetWidthFromRect(windowRecord->clientrect);
	if (PsychGetHeightFromRect(windowRecord->clientrect) < perfectUpToMaxDiameter) perfectUpToMaxDiameter = PsychGetHeightFromRect(windowRecord->clientrect);
	PsychCopyInDoubleArg(4, kPsychArgOptional, &perfectUpToMaxDiameter);

    // Compute number of subdivisions (slices) to provide a perfect oval, i.e., one subdivision for each
    // distance unit on the circumference of the oval.
    numSlices = 3.14159265358979323846 * perfectUpToMaxDiameter;

    if ((perfectUpToMaxDiameter != perfectUpToMaxDiameterOld) || (windowRecord->fillOvalDisplayList == 0)) {
        perfectUpToMaxDiameterOld = perfectUpToMaxDiameter;

        // Destroy old display list so it gets rebuilt with the new numSlices setting:
        if (isclassic && (windowRecord->fillOvalDisplayList != 0)) {
            glDeleteLists(windowRecord->fillOvalDisplayList, 1);
            windowRecord->fillOvalDisplayList = 0;
        }
    }

    // Already cached display list for filled ovals for this windowRecord available?
    if (isclassic && (windowRecord->fillOvalDisplayList == 0)) {
        // Nope. Create our prototypical filled oval:
        // Generate a filled disk of that radius and subdivision and store it in a display list:
        diskQuadric=gluNewQuadric();
        windowRecord->fillOvalDisplayList = glGenLists(1);
        glNewList(windowRecord->fillOvalDisplayList, GL_COMPILE);
        gluDisk(diskQuadric, 0, 1, (int) numSlices, 1);
        glEndList();
        gluDeleteQuadric(diskQuadric);
        // Display list ready for use in this and all future drawing calls for this 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, 0, &nrsize, NULL, FALSE);

	// 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;
	}
	else {
		// Multiple ovals provided. Set up the first one:
		PsychCopyRect(rect, &xy[0]);
	}

	// 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);
		}

		// Compute drawing parameters for ellipse:
		if (!IsPsychRectEmpty(rect)) {
			//The glu disk object location and size with a  center point and a radius,   
			//whereas FillOval 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;
				radius=rectX/2;
			} else if(rectX > rectY){
				xScale=1;
				yScale=rectY/rectX;
				radius=rectX/2;
			} else {
				yScale=1;
				xScale=rectX/rectY;
				radius=rectY/2;
			}

            if (isclassic) {
                // Draw: Set up position, scale and size via matrix transform:
                glPushMatrix();
                glTranslatef((float) xTranslate, (float) yTranslate, (float) 0);
                glScalef((float) (xScale * radius), (float) (yScale * radius), (float) 1);
                // Draw cached disk object (stored in display list):
                glCallList(windowRecord->fillOvalDisplayList);
                glPopMatrix();
            }
            else {
                PsychDrawDisc(windowRecord, (float) xTranslate, (float) yTranslate, (float) 0, (float) radius, (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.
	}
	
	// Mark end of drawing op. This is needed for single buffered drawing:
	PsychFlushGL(windowRecord);

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

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

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

    // Classic OpenGL-1/2?
    isclassic = PsychIsGLClassic(target);

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

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

    PsychCopyInDoubleArg(5, kPsychArgOptional, &rotationAngle);
    PsychCopyInIntegerArg(6, kPsychArgOptional, &filterMode);
    if (filterMode > 5) {
        PsychErrorExitMsg(PsychError_user, "filterMode needs to be negative for a specific blur level, or at most 5 for other modes.");    
    }

	// Copy in optional 'globalAlpha': We don't put restrictions on its valid range
	// anymore - That made sense for pure fixed function LDR rendering, but no longer
	// for HDR rendering or procedural shading.
    PsychCopyInDoubleArg(7, kPsychArgOptional, &globalAlpha);
    
    PsychSetDrawingTarget(target);
    PsychUpdateAlphaBlendingFactorLazily(target);
	
	if(PsychCopyInColorArg(8, kPsychArgOptional, &color)) {
		// set globalAlpha to DBL_MAX to signal that PsychBlitTexture() shouldn't
		// use this parameter and not set any modulate color, cause we do it.
		globalAlpha = DBL_MAX;
		
		// Setup global vertex color as modulate color for texture drawing:
		PsychCoerceColorMode(&color);

		// This call stores unclamped color in target->currentColor, as needed
		// if color is to be processed by some bound shader (procedural or filtershader)
		// inside PsychBlitTextureToDisplay():
		PsychConvertColorToDoubleVector(&color, target, (GLdouble*) &(target->currentColor));

		// Submit the same color to fixed function pipe attribute as well, in case no
		// shader is bound, or shader pulls from standard color attribute (we can't know yet):
        if (isclassic) {
            glColor4dv(target->currentColor);
        }
        else {
            PsychGLColor4f(target, (float) target->currentColor[0], (float) target->currentColor[1], (float) target->currentColor[2], (float) target->currentColor[3]);
        }
	}

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

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

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

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

    return(PsychError_none);

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

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

    psych_bool isclassic;
	int textureShader, backupShader;
	int specialFlags = 0;

    //all subfunctions should have these two lines.  
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    //Get the window structure for the onscreen window.  It holds the onscreen GL context which we will need in the
    //final step when we copy the texture from system RAM onto the screen.
    PsychErrorExit(PsychCapNumInputArgs(11));   	
    PsychErrorExit(PsychRequireNumInputArgs(2)); 	
    PsychErrorExit(PsychCapNumOutputArgs(0)); 
	
	// The target window is a fixed parameter:
    PsychAllocInWindowRecordArg(1, kPsychArgRequired, &target);

    // Classic OpenGL-1/2?
    isclassic = PsychIsGLClassic(target);
	
	// First get all source texture handles:
	PsychAllocInDoubleMatArg(2, kPsychArgRequired, &m, &n, &p, &texids);
	if ((p!=1) || (m>1 && n!=1) || (n>1 && m!=1)) PsychErrorExitMsg(PsychError_user, "The second argument must be either a row- or columnvector of valid texture handles.");
	// This is the number of texture handles:
	numTexs = m * n;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		// Next one...
	}

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

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

    return(PsychError_none);
}
Beispiel #13
0
void PsychSetArrayColor(PsychWindowRecordType *windowRecord, int i, int mc, double* colors, unsigned char *bytecolors)
{
    psych_bool isgles = !PsychIsGLClassic(windowRecord);

	if ((windowRecord->defaultDrawShader) || isgles) {
		// Draw shader assigned or OpenGL-ES in use. Need to feed color values into high-precision
		// alternative channel for unclamped, high-precision color handling:
		if (mc==3) {
			i=i * 3;
			if (colors) {
				// RGB double:
				currentColor[0]=colors[i++];
				currentColor[1]=colors[i++];
				currentColor[2]=colors[i++];
				currentColor[3]=1.0;
			}
			else {
				// RGB uint8:
				currentColor[0]=((double) bytecolors[i++] / 255.0);
				currentColor[1]=((double) bytecolors[i++] / 255.0);
				currentColor[2]=((double) bytecolors[i++] / 255.0);
				currentColor[3]=1.0;
			}
		}
		else {
			i=i * 4;
			if (colors) {
				// RGBA double:
				currentColor[0]=colors[i++];
				currentColor[1]=colors[i++];
				currentColor[2]=colors[i++];
				currentColor[3]=colors[i++];
			}
			else {
				// RGBA uint8:
				currentColor[0]=((double) bytecolors[i++] / 255.0);
				currentColor[1]=((double) bytecolors[i++] / 255.0);
				currentColor[2]=((double) bytecolors[i++] / 255.0);
				currentColor[3]=((double) bytecolors[i++] / 255.0);
			}
		}				

        if (isgles) {
            // GLES can only do glColor4f(), nothing else:
            glColor4f((float) currentColor[0], (float) currentColor[1], (float) currentColor[2], (float) currentColor[3]);
        }
        else {
            HDRglColor4dv(currentColor);
        }
	}
	else {
		// Standard fixed-function pipeline assigned: Feed into standard glColorXXX() calls:
		if (mc==3) {
			if (colors) {
				// RGB double:
				glColor3dv(&(colors[i*3]));
			}
			else {
				// RGB uint8:
				glColor3ubv(&(bytecolors[i*3]));
			}
		}
		else {
			if (colors) {
				// RGBA double:
				glColor4dv(&(colors[i*4]));
			}
			else {
				// RGBA uint8:
				glColor4ubv(&(bytecolors[i*4]));
			}					
		}
	}
	
	return;
}