File: SCREENBlendFunction.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 (158 lines) | stat: -rw-r--r-- 9,341 bytes parent folder | download | duplicates (7)
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
/*
	Psychtoolbox3/PsychSourceGL/Source/Common/Screen/SCREENBlendFunction.c	

	AUTHORS:

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

		All.
		
	HISTORY:

		01/08/05  awi		Wrote it.
		04/22/05  mk        Update of help text: Explain relationship to DrawTexture, DrawDots and DrawLines.
		04/06/08  mk		Add support for setup of color buffer writemask.

	DESCRIPTION:

		Set the GL blending function using glBlendFunc() and the color mask via glColorMask() for a specific window.
		Actually, it only stores the wanted settings. The real setup is happening whenever the window is selected
		for any drawing operations.

*/

#include "Screen.h"

// If you change the useString then also change the corresponding synopsis string in ScreenSynopsis.c
static char useString[] = "[sourceFactorOld, destinationFactorOld, colorMaskOld]=Screen('BlendFunction', windowIndex, [sourceFactorNew], [destinationFactorNew], [colorMaskNew]);";
//																									1            2				   3						4
static char synopsisString[] = 
	"Return or set the current alpha-blending mode and the color buffer writemask for window 'windowIndex'.\n"
	"Alpha blending is a way to combine color values of pixels already in the window with new color values from "
	"drawing commands. Alpha blending is disabled by default: If you overdraw some pixel location (x,y) in your window "
	"with a new source color value [Rs Gs Bs As], then the window location gets that color value assigned: I(x,y) = [Rs Gs Bs As]. "
	"However, OpenGL also allows you to combine such new color values with color values previously stored in that "
	"location. The old values are called destination colors [Rd Gd Bd Ad]. The way old and new destination and source "
	"colors are combined into new destination colors is called alpha-blending. Formally:\n"
	"New color at location (x,y) is [Rn Gn Bn An] = blendequation([Rs Gs Bs As], [Rd Gd Bd Ad]);\n where "
	"blendequation is a function that describes how the new [Rs Gs Bs As] color values and previous old "
	"values [Rd Gd Bd Ad] should be combined. You can choose the 'blendequation' from a set of defined "
	"blend equations via choice of the 'sourceFactorNew' and 'destinationFactorNew' arguments. See "
	"help PsychAlphaBlending and the help texts for the functions in that folder for possible choices "
	"of blend factors. The default setting of GL_ONE, GL_ZERO disables blending.\n"
	"The most common alpha-blending factors are sourceFactorNew = GL_SRC_ALPHA and destinationFactorNew = GL_ONE_MINUS_SRC_ALPHA "
	"They are needed for proper anti-aliasing (smoothing) by Screen('DrawLines'), Screen('DrawDots') and for drawing masked "
	"stimuli with the Screen('DrawTexture') command. See DotDemo, LinesDemo, AlphaImageDemo, GazeContingentDemo for a few "
	"applications of alpha-blending.\n\n"
	"This function also allows to return and set the color write mask for a window: You can prevent Psychtoolbox from drawing "
	"into and changing the content of one or more color channels by disabling the color channel for writing. This allows to "
	"perform drawing commands that only affect, e.g., the red chahnnel, but not the blue, green or alpha channel. "
	"You choose the channels by specification of the 'colorMaskNew' vector: The first element selects if writing to the "
	"red color channel are allowed (value greater than zero) or disallowed (value equal zero). The 2nd element selects the "
	"green channels state, the 3rd element selects the blue channels state and the 4th element selects the alpha channels "
	"state. E.g., setting colorMaskNew equal to [1 1 0 0] would allow updates of the red and green channel, but not of the "
	"blue and alpha channel. A setting of [0 1 0 1] would allow updates to the green- and alpha channel, but not the red- "
	"and blue channel etc. The default writemask is 'all enabled' ie. [1 1 1 1].\n\n"
	"Settings for alpha-blending and color write mask are per window: They can be set individually for each onscreen window, "
	"offscreen window or texture. ";

static char seeAlsoString[] = "DrawDots, DrawLines, DrawTexture";	 

PsychError SCREENBlendFunction(void)
{
	PsychWindowRecordType 	*windowRecord;
	GLenum					oldSource, oldDestination, newSource, newDestination;
	char					*oldSoureStr, *oldDestinationStr, *newSourceStr, *newDestinationStr;
	int						oldSourceStrSize, oldDestinationStrSize, isSourceStringValid, isDestinationStringValid;
	psych_bool					isSourceSupplied, isDestinationSupplied, isSourceChoiceValid, isDestinationChoiceValid;
	double					*oldColorMask, *newColorMask;
	int						m, n, p;
	
	//all subfunctions should have these two lines.  
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

	PsychErrorExit(PsychCapNumInputArgs(4));		//The maximum number of inputs
	PsychErrorExit(PsychRequireNumInputArgs(1));	//The required number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(3));		//The maximum number of outputs

	//Get the window record or exit with an error if the windex was bogus.
	PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);

	//Retreive the old source and destination factors and return them from the Screen call as strings
	PsychGetAlphaBlendingFactorsFromWindow(windowRecord, &oldSource, &oldDestination);

	oldSourceStrSize=PsychGetAlphaBlendingFactorStringFromConstant(oldSource, NULL);
	oldDestinationStrSize=PsychGetAlphaBlendingFactorStringFromConstant(oldDestination, NULL);
	
	oldSoureStr=(char *)malloc(sizeof(char) * oldSourceStrSize);
	oldDestinationStr=(char *)malloc(sizeof(char) * oldDestinationStrSize);

	PsychGetAlphaBlendingFactorStringFromConstant(oldSource, oldSoureStr);
	PsychGetAlphaBlendingFactorStringFromConstant(oldDestination, oldDestinationStr);

	PsychCopyOutCharArg(1, kPsychArgOptional, oldSoureStr);
	PsychCopyOutCharArg(2, kPsychArgOptional, oldDestinationStr);
	
	free((void *)oldSoureStr);
	free((void *)oldDestinationStr);

	//Get the new settings if they are present and set them.
	newSource=oldSource;
	newDestination=oldDestination;

	isSourceSupplied= PsychAllocInCharArg(2, kPsychArgOptional, &newSourceStr);
	isDestinationSupplied= PsychAllocInCharArg(3, kPsychArgOptional, &newDestinationStr);

	if(isSourceSupplied){
		isSourceStringValid=PsychGetAlphaBlendingFactorConstantFromString(newSourceStr, &newSource);
		if(!isSourceStringValid) PsychErrorExitMsg(PsychError_user, "Supplied string argument 'sourceFactorNew' is invalid");

		isSourceChoiceValid=PsychValidateBlendingConstantForSource(newSource);
		if(!isSourceChoiceValid) PsychErrorExitMsg(PsychError_user, "The blending factor supplied for the source is only valid only for the destination");
	}

	if(isDestinationSupplied){
		isDestinationStringValid=PsychGetAlphaBlendingFactorConstantFromString(newDestinationStr, &newDestination);
		if(!isDestinationStringValid) PsychErrorExitMsg(PsychError_user, "Supplied string argument 'destinationFactorNew' is invalid");

		isDestinationChoiceValid=PsychValidateBlendingConstantForDestination(newDestination);
		if(!isDestinationChoiceValid) PsychErrorExitMsg(PsychError_user, "The blending factor supplied for the destination is only valid only for the source");
	}

	PsychStoreAlphaBlendingFactorsForWindow(windowRecord, newSource, newDestination);

	// Check if alpha blending is possible for this windowRecord:
	if ((newSource != GL_ONE || newDestination != GL_ZERO) && !((windowRecord->bpc < 16) || (windowRecord->bpc == 16 && (windowRecord->gfxcaps & kPsychGfxCapFPBlend16)) || (windowRecord->bpc == 32 && (windowRecord->gfxcaps & kPsychGfxCapFPBlend32)) || ((windowRecord->bpc == 16) && (windowRecord->imagingMode & kPsychNeed16BPCFixed)))) {
		// Nope. Alpha blending requested but not possible for this windowRecord with this gfx-hardware.
		if (PsychPrefStateGet_Verbosity() > 1) {
			printf("PTB-WARNING: Screen('Blendfunction') called to enable alpha-blending on a window (handle=%i) which doesn't support\n", windowRecord->windowIndex);
			printf("PTB-WARNING: alpha-blending at its current color resolution of %i bits per color component on your hardware.\n", windowRecord->bpc);
			printf("PTB-WARNING: Won't enable blending. Either lower the color resolution of the window (see help PsychImaging) or\n");
			printf("PTB-WARNING: upgrade your graphics hardware.\n\n");
		}
	}
	
	// Create return array with encoded old colormask:
	PsychAllocOutDoubleMatArg(3, kPsychArgOptional, 1, 4, 1, &oldColorMask);
	oldColorMask[0] = (windowRecord->colorMask[0]) ? 1 : 0;
	oldColorMask[1] = (windowRecord->colorMask[1]) ? 1 : 0;
	oldColorMask[2] = (windowRecord->colorMask[2]) ? 1 : 0;
	oldColorMask[3] = (windowRecord->colorMask[3]) ? 1 : 0;

	// Any new colormask provided?
	if (PsychAllocInDoubleMatArg(4, kPsychArgOptional, &m, &n, &p, &newColorMask)) {
		// Yes. Assign it:
		if (p!=1 || m*n != 4)  PsychErrorExitMsg(PsychError_user, "The colorMaskNew argument must be a 4 element row- or column vector!");

		windowRecord->colorMask[0] = (newColorMask[0] > 0) ? GL_TRUE : GL_FALSE;
		windowRecord->colorMask[1] = (newColorMask[1] > 0) ? GL_TRUE : GL_FALSE;
		windowRecord->colorMask[2] = (newColorMask[2] > 0) ? GL_TRUE : GL_FALSE;
		windowRecord->colorMask[3] = (newColorMask[3] > 0) ? GL_TRUE : GL_FALSE;
	}
	
	return(PsychError_none);
}