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 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
|
/*
* SCREENTransformTexture.c
*
* AUTHORS:
*
* mario.kleiner.de@gmail.com mk
*
* PLATFORMS:
*
* All.
*
* HISTORY:
*
* 01/26/07 mk Wrote it.
*
*/
#include "Screen.h"
// If you change useString then also change the corresponding synopsis string in ScreenSynopsis.c
static char useString[] = "transtexid = Screen('TransformTexture', sourceTexture, transformProxyPtr [, sourceTexture2][, targetTexture] [, specialFlags]);";
// 1 1 2 3 4 5
static char synopsisString[] =
"Apply an image processing operation to a texture 'sourceTexture' and store the processed result either in 'targetTexture' if "
"provided, or in a new texture (if 'targetTexture' is not provided). Use the data in the optional 'sourceTexture2' as well if "
"provided. This could be, e.g., a lookup table or a 2nd image for stereo processing. Return a handle 'transtexid' to the "
"processed texture.\n"
"If 'targetTexture' was provided and suitable then the returned 'transtexid' will be identical to 'targetTexture'. For maximum "
"efficiency in iterative processing, you should hand the 'transtexid' from a previous call to Screen('TransformTexture') back "
"into a successive call as 'targetTexture', so the same container can be recycled. At first invocation you could hand in an "
"empty [] 'targetTexture' to leave optimal choice of the format to the function. If you want to hand your self-made 'targetTexture' "
"then using a handle created via Screen('OpenOffscreenWindow') will be slightly more efficient than using a handle created via "
"Screen('MakeTexture').\n"
"The image processing operation is defined in the processing hook chain 'UserDefinedBlit' of the proxy object 'transformProxyPtr'.\n"
"'specialFlags' optional flags to alter operation of this function: kPsychAssumeTextureNormalized - Assume source texture(s) are "
"already in a normalized upright orientation. This can speed up processing, but it can lead to wrong results if the textures "
"are not normalized and the imaging operation is non-isotropic - Use with care. A setting of specialFlags == 2 will ask to create "
"or set the resulting 'transtexid' texture for high-precision drawing, see same setting in Screen('MakeTexture') for explanation.\n"
"Read 'help PsychGLImageProcessing' for more infos on how to use this function.";
static char seeAlsoString[] = "";
PsychError SCREENTransformTexture(void)
{
PsychWindowRecordType *sourceRecord, *targetRecord, *proxyRecord, *sourceRecord2;
int testarg, specialFlags, usefloatformat, d;
// All subfunctions should have these two lines.
PsychPushHelp(useString, synopsisString, seeAlsoString);
if (PsychIsGiveHelp()) { PsychGiveHelp(); return(PsychError_none); };
PsychErrorExit(PsychCapNumInputArgs(5));
PsychErrorExit(PsychRequireNumInputArgs(2));
PsychErrorExit(PsychCapNumOutputArgs(1));
// OpenGL FBO's supported? Otherwise this is a no-go...
if (glBindFramebufferEXT == NULL || glUseProgram == NULL) {
// Game over!
printf("PTB-ERROR: Sorry, your graphics driver & hardware does not support the required OpenGL framebuffer object extension or\n");
printf("PTB-ERROR: the OpenGL shading language for hardware accelerated fragment processing. This function is therefore disabled.\n");
printf("PTB-ERROR: You will need at least a NVidia GeforceFX-5200, a ATI Radeon 9600 or a Intel GMA-950 graphics card for this\n");
printf("PTB-ERROR: to work. If you have such a card (or a more recent one) then you'll need to update your graphics drivers.\n\n");
PsychErrorExitMsg(PsychError_user, "Screen('TransformTexture') command unsupported on your combination of graphics hardware & driver.");
}
// Get the window structure for the source texture.
PsychAllocInWindowRecordArg(1, TRUE, &sourceRecord);
if (!PsychIsTexture(sourceRecord))
PsychErrorExitMsg(PsychError_user, "'sourceTexture' argument must be a handle to a texture or offscreen window.");
// Get the window structure for the proxy object.
PsychAllocInWindowRecordArg(2, TRUE, &proxyRecord);
if (proxyRecord->windowType != kPsychProxyWindow)
PsychErrorExitMsg(PsychError_user, "'transformProxyPtr' argument must be a handle to a proxy object.");
// Test if optional specialFlags are provided:
specialFlags = 0;
PsychCopyInIntegerArg(5, FALSE, &specialFlags);
// Activate rendering context of the proxy object and soft-reset the drawing engine,
// so we're in a well defined state. The value 1 means: Reset safely, ie. do any
// framebuffer backups that might be needed before NULL-ing the binding:
PsychSetDrawingTarget((PsychWindowRecordType*) 0x1);
PsychSetGLContext(proxyRecord);
// Save all state:
glPushAttrib(GL_ALL_ATTRIB_BITS);
// Disable alpha-blending:
glDisable(GL_BLEND);
// Reset color write mask to "all enabled"
glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
// Disable any shaders:
PsychSetShader(proxyRecord, 0);
// Transform sourceRecord source texture into a normalized, upright texture if it isn't already in
// that format. We require this standard orientation for simplified shader design.
if (!(specialFlags & 1))
PsychNormalizeTextureOrientation(sourceRecord);
// Test if optional 2nd source texture is provided:
testarg = 0;
PsychCopyInIntegerArg(3, FALSE, &testarg);
if (testarg != 0) {
// Tes. Get the window structure for the 2nd source texture.
PsychAllocInWindowRecordArg(3, TRUE, &sourceRecord2);
if (!PsychIsTexture(sourceRecord2))
PsychErrorExitMsg(PsychError_user, "'sourceTexture2' argument must be a handle to a texture or offscreen window.");
// Transform sourceRecord2 source texture into a normalized, upright texture if it isn't already in
// that format. We require this standard orientation for simplified shader design.
if (!(specialFlags & 1))
PsychNormalizeTextureOrientation(sourceRecord2);
}
else {
// No secondary source texture:
sourceRecord2 = NULL;
}
// Restore proper rendering context:
PsychSetGLContext(proxyRecord);
// Test if optional target texture is provided:
testarg = 0;
PsychCopyInIntegerArg(4, FALSE, &testarg);
// Do we need to create a new one from scratch?
if (testarg == 0) {
// No valid textureHandle provided. Create a new empty textureRecord which clones some
// of the properties of the sourceRecord
targetRecord = NULL;
PsychCreateWindowRecord(&targetRecord);
PsychInitWindowRecordTextureFields(targetRecord);
targetRecord->windowType=kPsychTexture;
targetRecord->screenNumber = sourceRecord->screenNumber;
// Assign parent window and copy its inheritable properties:
PsychAssignParentWindow(targetRecord, sourceRecord);
targetRecord->depth = sourceRecord->depth;
// Assume this texture has four channels.
targetRecord->nrchannels = 4;
PsychCopyRect(targetRecord->rect, sourceRecord->rect);
PsychCopyRect(targetRecord->clientrect, targetRecord->rect);
targetRecord->texturetarget = sourceRecord->texturetarget;
// Orientation is set to 2 - like an upright Offscreen window texture:
targetRecord->textureOrientation = 2;
// Mark it valid and return handle to userspace:
PsychSetWindowRecordValid(targetRecord);
}
else {
// Get the window structure for the target texture.
PsychAllocInWindowRecordArg(4, TRUE, &targetRecord);
if (!PsychIsTexture(targetRecord))
PsychErrorExitMsg(PsychError_user, "'targetTexture' argument must be a handle to a texture or offscreen window.");
}
// Make sure our source textures have at least a pseudo FBO for read-access:
PsychCreateShadowFBOForTexture(sourceRecord, FALSE, -1);
if (sourceRecord2)
PsychCreateShadowFBOForTexture(sourceRecord2, FALSE, -1);
// Make sure the target texture is upright/normalized:
if (!(specialFlags & 1))
PsychNormalizeTextureOrientation(targetRecord);
// Make sure our target texture has a full-blown FBO attached as a rendertarget.
// As our proxy object defines the image processing ops, it also defines the
// required imagingMode properties for the target texture:
PsychCreateShadowFBOForTexture(targetRecord, TRUE, proxyRecord->imagingMode);
// Assign GLSL filter-/lookup-shaders if needed: usefloatformat is queried.
// The 'userRequest' flag is set depending on specialFlags setting & 2.
glBindTexture(targetRecord->texturetarget, targetRecord->textureNumber);
glGetTexLevelParameteriv(targetRecord->texturetarget, 0, GL_TEXTURE_RED_SIZE, (GLint*) &d);
if (d <= 0)
glGetTexLevelParameteriv(targetRecord->texturetarget, 0, GL_TEXTURE_LUMINANCE_SIZE, (GLint*) &d);
glBindTexture(targetRecord->texturetarget, 0);
usefloatformat = 0;
if (d == 16) usefloatformat = 1;
if (d >= 32) usefloatformat = 2;
PsychAssignHighPrecisionTextureShaders(targetRecord, sourceRecord, usefloatformat, (specialFlags & 2) ? 1 : 0);
// Make sure our proxy has suitable bounce buffers if we need any:
if (proxyRecord->imagingMode & (kPsychNeedDualPass | kPsychNeedMultiPass)) {
// Needs multi-pass processing. Create bounce buffer if neccessary:
PsychCopyRect(proxyRecord->rect, targetRecord->rect);
PsychCopyRect(proxyRecord->clientrect, targetRecord->rect);
// Build FBO for bounce-buffering. This will always be upright/normalized,
// so no need to normalize "texture orientation" for proxyRecord bounce buffers:
PsychCreateShadowFBOForTexture(proxyRecord, TRUE, proxyRecord->imagingMode);
}
// Make sure we don't have VRAM memory feedback loops:
if ((sourceRecord->textureNumber == targetRecord->textureNumber) ||
(sourceRecord2 && (sourceRecord2->textureNumber == targetRecord->textureNumber)))
PsychErrorExitMsg(PsychError_user, "Source texture and target texture must be different!");
// Apply image processing operation: Use ressources and OpenGL context of proxyRecord, run user defined blit chain,
// Don't supply user specific data (NULL), don't supply override blitter (NULL), source is read-only (TRUE), no
// swizzle allowed (FALSE), sourceRecord is source, targetRecord is destination, bounce buffers provided by proxyRecord,
// no secondary FBO available (NULL).
PsychPipelineExecuteHook(proxyRecord, kPsychUserDefinedBlit, NULL, NULL, TRUE, FALSE,
&(sourceRecord->fboTable[sourceRecord->drawBufferFBO[0]]), (sourceRecord2) ? &(sourceRecord2->fboTable[sourceRecord2->drawBufferFBO[0]]) : NULL,
&(targetRecord->fboTable[targetRecord->drawBufferFBO[0]]), (proxyRecord->drawBufferFBO[0]!=-1) ? &(proxyRecord->fboTable[proxyRecord->drawBufferFBO[0]]) : NULL);
// Restore previous settings:
glPopAttrib();
// Set "dirty" flag on texture: (Ab)used to trigger regeneration of mip-maps during texture drawing of mip-mapped textures.
targetRecord->needsViewportSetup = TRUE;
//Return the window index and the rect argument.
PsychCopyOutDoubleArg(1, FALSE, targetRecord->windowIndex);
// Done.
return(PsychError_none);
}
|