File: SCREENFrameRect.c

package info (click to toggle)
psychtoolbox-3 3.0.19.14.dfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 86,796 kB
  • sloc: ansic: 176,245; cpp: 20,103; objc: 5,393; sh: 2,753; python: 1,397; php: 384; makefile: 193; java: 113
file content (181 lines) | stat: -rw-r--r-- 6,658 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/*
	SCREENFrameRect.c		

	AUTHORS:

	Allen.Ingling@nyu.edu			awi 
	mario.kleiner@tuebingen.mpg.de	mk

	PLATFORMS:	
	
	All.

	HISTORY:

		07/23/04	awi		Created.
		10/12/04	awi		In useString: moved commas to inside [].
		2/25/05		awi		Added call to PsychUpdateAlphaBlendingFactorLazily().  Drawing now obeys settings by Screen('BlendFunction').
		  

	TO DO:

*/


#include "Screen.h"

// If you change useString then also change the corresponding synopsis string in ScreenSynopsis.c
static char useString[] = "Screen('FrameRect', windowPtr [,color] [,rect] [,penWidth]);";
//                                             1           2        3       4          
static char synopsisString[] = 
	"Draw the outline of a rectangle \"rect\"."
	" \"color\" is the clut index (scalar or [r g b] triplet or [r g b a] quadruple) "
	"that you want to poke into each pixel;  default produces white with the standard CLUT for this "
	"window's pixelSize. Default \"rect\" is entire window.\n"
	"Instead of framing one rectangle, you can also specify a list of multiple rectangles to be "
	"framed - this is much faster when you need to draw many rectangles per frame. To frame n "
	"rectangles, provide \"rect\" as a 4 rows by n columns matrix, each column specifying one "
	"rectangle, e.g., rect(1,5)=left border of 5th rectange, rect(2,5)=top border of 5th rectangle, "
	"rect(3,5)=right border of 5th rectangle, rect(4,5)=bottom border of 5th rectangle. If the "
	"rectangles should have different colors, then provide \"color\" as a 3 or 4 row by n column "
	"matrix, the i'th column specifiying the color of the i'th rectangle. You can also specify a "
    "single pen size or a vector pen sizes (one for each rectangle) to control the thickness of "
	"the lines used to frame the rect. Default \"penWidth\" is 1 pixel unit. ";
	
static char seeAlsoString[] = "FillRect";	

PsychError SCREENFrameRect(void)  
{	
	PsychRectType					rect;
	PsychWindowRecordType			*windowRecord;
	psych_bool						isArgThere;
	double							penSize, lf, fudge;
    double							*xy, *colors, *penSizes;
	unsigned char					*bytecolors;
	int								numRects, i, j, nc, mc, nrsize;

	//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 tweakable correction factor for framerect: Not an option on non-classic GL anymore.
	lf = (PsychIsGLClassic(windowRecord)) ? PsychPrefStateGet_FrameRectCorrection() : -1;
	
	// Query, allocate and copy in all vectors...
	numRects = 4;
	nrsize = 0;
	colors = NULL;
	bytecolors = NULL;
	penSizes = NULL;
	
	// 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);

	// Default rect is fullscreen:
	PsychCopyRect(rect, windowRecord->clientrect);

	// Only up to one rect provided?
	if (numRects <= 1) {
		// Get the rect and draw it
		isArgThere=PsychCopyInRectArg(kPsychUseDefaultArgPosition, FALSE, rect);	
		if (isArgThere && IsPsychRectEmpty(rect)) return(PsychError_none);
		numRects = 1;
	}

	// Pen size starts as "undefined", just to make sure it gets initially set:
	penSize = -DBL_MAX;
	
	// Framed rect drawing loop:
	for (i=0; i<numRects; i++) {
		// Multiple rects to draw or single iteration to draw provided rect?
		if (numRects > 1) {
			// Multi-Rect drawing: Assign next rect from array and setup corresponding
			// color and penSize...

			// Assign rect:
			rect[kPsychLeft] = xy[i*4 + 0];
			rect[kPsychTop] = xy[i*4 + 1];
			rect[kPsychRight] = xy[i*4 + 2];
			rect[kPsychBottom] = xy[i*4 + 3];

			// Per rect color provided?
			if (nc>1) {
				// Yes. Set color for this specific rect:
				PsychSetArrayColor(windowRecord, i, mc, colors, bytecolors);
			}
		}
		else {
			// Only one single rect to draw in this single loop iteration.
			// The rect is already set up in 'rect', and the drawing color has
			// been set as well by PsychPrepareRenderBatch(). penSize has been
			// set by that routine as well in penSizes[0], so we don't have
			// anything to do here...
			// NO OP.
		}
		
		j = (nrsize > 1) ? i : 0; 
		
        if (penSizes[j] != penSize) {
			penSize = penSizes[j];
			if (lf != -1) glLineWidth((GLfloat) penSize);
		}
		
		if (IsPsychRectEmpty(rect)) continue;

		if (lf == -1) {
			// New style rendering: More robust against variations in GPU implementations:
			fudge = penSize;
            GLRECTd(rect[kPsychLeft], rect[kPsychTop], rect[kPsychRight], rect[kPsychTop] + fudge);
			GLRECTd(rect[kPsychLeft], rect[kPsychBottom], rect[kPsychRight], rect[kPsychBottom] - fudge);
			GLRECTd(rect[kPsychLeft], rect[kPsychTop]+fudge, rect[kPsychLeft]+fudge, rect[kPsychBottom]-fudge);
			GLRECTd(rect[kPsychRight]-fudge, rect[kPsychTop]+fudge, rect[kPsychRight], rect[kPsychBottom]-fudge);
		}
		else {
			// Old style: Has a couple of problems in corner cases. Left for now as reference...
			if (penSize > 1) {
				// Width > 1
				
				fudge = (penSize > 1) ? lf * penSize/2 : 0.0;
				
				glBegin(GL_LINES);
				// Draw 4 separate segments, extend the left and right
				// vertical segments by half a penWidth.
				glVertex2d(rect[kPsychLeft], rect[kPsychTop] - fudge);
				glVertex2d(rect[kPsychLeft], rect[kPsychBottom] + fudge);
				glVertex2d(rect[kPsychRight], rect[kPsychTop]);
				glVertex2d(rect[kPsychLeft], rect[kPsychTop]);
				glVertex2d(rect[kPsychRight], rect[kPsychBottom] + fudge);
				glVertex2d(rect[kPsychRight], rect[kPsychTop] - fudge);
				glVertex2d(rect[kPsychRight], rect[kPsychBottom]);
				glVertex2d(rect[kPsychLeft], rect[kPsychBottom]);
				glEnd();			
			}
			else {
				// Width <= 1: Simple case...
				glBegin(GL_LINE_LOOP);
				glVertex2d(rect[kPsychLeft], rect[kPsychBottom]);
				glVertex2d(rect[kPsychLeft], rect[kPsychTop]);
				glVertex2d(rect[kPsychRight], rect[kPsychTop]);
				glVertex2d(rect[kPsychRight], rect[kPsychBottom]);
				glEnd();
			}
		}
		// Next rect...
	}
	
	// Need to reset line width?
	if (penSize!=1 && lf!=-1) glLineWidth(1);

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

	return(PsychError_none);
}