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); }
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 SCREENFillOval(void) { PsychRectType rect; double numSlices, radius, xScale, yScale, xTranslate, yTranslate, rectY, rectX; PsychWindowRecordType *windowRecord; psych_bool isArgThere; 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); perfectUpToMaxDiameter = PsychGetWidthFromRect(windowRecord->clientrect); if (PsychGetHeightFromRect(windowRecord->clientrect) < perfectUpToMaxDiameter) perfectUpToMaxDiameter = PsychGetHeightFromRect(windowRecord->clientrect); PsychCopyInDoubleArg(4, kPsychArgOptional, &perfectUpToMaxDiameter); if ((perfectUpToMaxDiameter != perfectUpToMaxDiameterOld) || (windowRecord->fillOvalDisplayList == 0)) { perfectUpToMaxDiameterOld = 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; // Destroy old display list so it gets rebuilt with the new numSlices setting: if (windowRecord->fillOvalDisplayList != 0) { glDeleteLists(windowRecord->fillOvalDisplayList, 1); windowRecord->fillOvalDisplayList = 0; } } // Already cached display list for filled ovals for this windowRecord available? if (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); // 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 if(rectY > rectX){ yScale=1; xScale=rectX/rectY; radius=rectY/2; } // Draw: Set up position, scale and size via matrix transform: glPushMatrix(); glTranslated(xTranslate,yTranslate,0); glScaled(xScale * radius, yScale * radius, 1); // Draw cached disk object (stored in display list): glCallList(windowRecord->fillOvalDisplayList); // Done. glPopMatrix(); } // 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); }