void moglfree(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { // Retrieve ptr to membuffer, encoded as double and convert it into a void* void* ptr = PsychDoubleToPtr((GLdouble) mxGetScalar(prhs[0])); // Free memory buffer: PsychFreeTemp(ptr, 1); }
void gl_selectbuffer( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { // Retrieve memory ptr from double argument: GLuint* ptr = (GLuint*) PsychDoubleToPtr((GLdouble) mxGetScalar(prhs[1])); if (NULL == glSelectBuffer) mogl_glunsupported("glSelectBuffer"); glSelectBuffer((GLsizei)mxGetScalar(prhs[0]), ptr); }
void moglcopybuffertomatrix(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { int dims, type; GLenum mattype; GLfloat* dst; // Retrieve ptr to membuffer, encoded as double and convert it into a void* void* src = PsychDoubleToPtr((GLdouble) mxGetScalar(prhs[0])); // Retrieve size of buffer pointed to by src: unsigned int n = PsychGetBufferSizeForPtr(src); // Retrieve max number of bytes to copy: unsigned int nmax = (unsigned int) mxGetScalar(prhs[2]); if (nmax < n) n = nmax; // Retrieve type of matrix to create: mattype = (GLenum) mxGetScalar(prhs[1]); switch(mattype) { case GL_DOUBLE: type = mxDOUBLE_CLASS; dims = n / sizeof(double); if (dims * sizeof(double) < n) dims++; break; case GL_FLOAT: type = mxSINGLE_CLASS; dims = n / sizeof(float); if (dims * sizeof(float) < n) dims++; break; case GL_UNSIGNED_INT: type = mxUINT32_CLASS; dims = n / sizeof(unsigned int); if (dims * sizeof(unsigned int) < n) dims++; break; case GL_UNSIGNED_BYTE: type = mxUINT8_CLASS; dims = n / sizeof(unsigned char); if (dims * sizeof(unsigned char) < n) dims++; break; default: mexErrMsgTxt("MOGL-ERROR: Unknown matrix type requested in moglgetbuffer()! Ignored."); } // Allocate the beast: plhs[0] = mxCreateNumericArray(1, &dims, type, mxREAL); // Retrieve pointer to output matrix: dst = (GLfloat*) mxGetData(plhs[0]); // Do the copy: memcpy(dst, src, n); }
void gl_feedbackbuffer( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { // Retrieve memory ptr from double argument: GLfloat* ptr = (GLfloat*) PsychDoubleToPtr((GLdouble) mxGetScalar(prhs[2])); if (NULL == glFeedbackBuffer) mogl_glunsupported("glFeedbackBuffer"); glFeedbackBuffer((GLsizei)mxGetScalar(prhs[0]), (GLenum)mxGetScalar(prhs[1]), ptr); }
void moglcopymatrixtobuffer(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { // Retrieve ptr to membuffer, encoded as double and convert it into a void* void* dst = PsychDoubleToPtr((GLdouble) mxGetScalar(prhs[1])); // Retrieve pointer to input matrix: GLfloat* src = (GLfloat*) mxGetData(prhs[0]); // Retrieve size of buffer pointed to by dst: unsigned int nmax = PsychGetBufferSizeForPtr(dst); // Set final size of data to copy: unsigned int nin = (unsigned int) mxGetScalar(prhs[2]); if (nin > nmax) nin = nmax; // Do the copy: memcpy(dst, src, nin); }
PsychError SCREENSetOpenGLTextureFromMemPointer(void) { PsychWindowRecordType *windowRecord, *textureRecord; int w, h, d, testarg, upsidedown, glinternalformat, glexternaltype, glexternalformat; double doubleMemPtr; GLenum target = 0; w=h=d=-1; doubleMemPtr = 0; upsidedown = 0; //all subfunctions should have these two lines. PsychPushHelp(useString, synopsisString, seeAlsoString); if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);}; PsychErrorExit(PsychCapNumInputArgs(11)); // The maximum number of inputs PsychErrorExit(PsychRequireNumInputArgs(5)); // The required number of inputs PsychErrorExit(PsychCapNumOutputArgs(2)); // 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); // Get the texture record from the texture record argument. // Check if either none ( [] or '' ) or the special value zero was // provided as Psychtoolbox textureHandle. In that case, we create a new // empty texture record instead of reusing an existing one. testarg=0; PsychCopyInIntegerArg(2, FALSE, &testarg); if (testarg==0) { // No valid textureHandle provided. Create a new empty textureRecord. PsychCreateWindowRecord(&textureRecord); textureRecord->windowType=kPsychTexture; textureRecord->screenNumber = windowRecord->screenNumber; textureRecord->targetSpecific.contextObject = windowRecord->targetSpecific.contextObject; textureRecord->targetSpecific.deviceContext = windowRecord->targetSpecific.deviceContext; textureRecord->targetSpecific.glusercontextObject = windowRecord->targetSpecific.glusercontextObject; textureRecord->colorRange = windowRecord->colorRange; // Copy imaging mode flags from parent: textureRecord->imagingMode = windowRecord->imagingMode; // Mark it valid and return handle to userspace: PsychSetWindowRecordValid(textureRecord); } else { // None of the special values provided. We assume its a handle to a valid // and existing PTB texture and try to retrieve the textureRecord: PsychAllocInWindowRecordArg(2, TRUE, &textureRecord); } // Is it a textureRecord? if (!PsychIsTexture(textureRecord)) { PsychErrorExitMsg(PsychError_user, "You tried to set texture information on something else than a texture!"); } // Query double-encoded memory pointer: PsychCopyInDoubleArg(3, TRUE, &doubleMemPtr); // Query width: PsychCopyInIntegerArg(4, TRUE, &w); // Query height: PsychCopyInIntegerArg(5, TRUE, &h); // Query depth: PsychCopyInIntegerArg(6, TRUE, &d); // Query (optional) upsidedown - flag: PsychCopyInIntegerArg(7, FALSE, &upsidedown); // Query (optional) OpenGL texture target: PsychCopyInIntegerArg(8, FALSE, (int*) &target); // Query (optional) full format spec: glinternalformat = 0; PsychCopyInIntegerArg(9, FALSE, &glinternalformat); if (glinternalformat>0) { // Ok copy the (now non-optional) remaining format spec: PsychCopyInIntegerArg(10, TRUE, &glexternalformat); PsychCopyInIntegerArg(11, TRUE, &glexternaltype); } // Safety checks: if (doubleMemPtr == 0) { PsychErrorExitMsg(PsychError_user, "You tried to set invalid (NULL) imagePtr."); } if (w<=0) { PsychErrorExitMsg(PsychError_user, "You tried to set invalid (negative) texture width."); } if (h<=0) { PsychErrorExitMsg(PsychError_user, "You tried to set invalid (negative) texture height."); } if (d<=0) { PsychErrorExitMsg(PsychError_user, "You tried to set invalid (negative) texture depth."); } if (d>4) { PsychErrorExitMsg(PsychError_user, "You tried to set invalid (greater than four) texture depth."); } if (target!=0 && target!=GL_TEXTURE_RECTANGLE_EXT && target!=GL_TEXTURE_2D) { PsychErrorExitMsg(PsychError_user, "You tried to set invalid texture target."); } // Activate OpenGL rendering context of windowRecord and make it the active drawing target: PsychSetGLContext(windowRecord); PsychSetDrawingTarget(windowRecord); PsychTestForGLErrors(); // Ok, setup texture record for texture: PsychInitWindowRecordTextureFields(textureRecord); textureRecord->depth = d * 8; textureRecord->nrchannels = d; PsychMakeRect(textureRecord->rect, 0, 0, w, h); // Override texture target, if one was provided: if (target!=0) textureRecord->texturetarget = target; // Orientation is normally set to 2 - like an upright Offscreen window texture. // If upsidedown flag is set, then we do 3 - an upside down Offscreen window texture. textureRecord->textureOrientation = (upsidedown>0) ? 3 : 2; if (glinternalformat!=0) { textureRecord->textureinternalformat = glinternalformat; textureRecord->textureexternalformat = glexternalformat; textureRecord->textureexternaltype = glexternaltype; } // Setting memsize to zero prevents unwanted free() operation in PsychDeleteTexture... textureRecord->textureMemorySizeBytes = 0; // This will retrieve an OpenGL compatible pointer to the raw pixel data and assign it to our texmemptr: textureRecord->textureMemory = (GLuint*) PsychDoubleToPtr(doubleMemPtr); // printf("InTexPtr %p , %.20e", PsychDoubleToPtr(doubleMemPtr), doubleMemPtr); // Let PsychCreateTexture() do the rest of the job of creating, setting up and // filling an OpenGL texture with memory buffers image content: PsychCreateTexture(textureRecord); // Return new (or old) PTB textureHandle for this texture: PsychCopyOutDoubleArg(1, FALSE, textureRecord->windowIndex); PsychCopyOutRectArg(2, FALSE, textureRecord->rect); // Done. return(PsychError_none); }
PsychError SCREENGetCapturedImage(void) { PsychWindowRecordType *windowRecord; PsychWindowRecordType *textureRecord; PsychRectType rect; double summed_intensity; int capturehandle = -1; int waitForImage = TRUE; int specialmode = 0; double timeout, tnow; double presentation_timestamp = 0; int rc=-1; double targetmemptr = 0; double* tsummed = NULL; psych_uint8 *targetmatrixptr = NULL; static rawcapimgdata rawCaptureBuffer = {0, 0, 0, NULL}; // All sub functions should have these two lines PsychPushHelp(useString, synopsisString, seeAlsoString); if(PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none);}; PsychErrorExit(PsychCapNumInputArgs(6)); // Max. 6 input args. PsychErrorExit(PsychRequireNumInputArgs(2)); // Min. 2 input args required. PsychErrorExit(PsychCapNumOutputArgs(4)); // Max. 4 output args. // Get the window record from the window record argument and get info from the window record PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord); // Only onscreen windows allowed: if(!PsychIsOnscreenWindow(windowRecord) && !PsychIsOffscreenWindow(windowRecord)) { PsychErrorExitMsg(PsychError_user, "GetCapturedImage called on something else than an onscreen window or offscreen window."); } // Get the handle: PsychCopyInIntegerArg(2, TRUE, &capturehandle); if (capturehandle==-1) { PsychErrorExitMsg(PsychError_user, "GetCapturedImage called without valid handle to a capture object."); } // Get the 'waitForImage' flag: If waitForImage == true == 1, we'll do a blocking wait for // arrival of a new image. Otherwise we will return with a 0-Handle if there // isn't any new image available. PsychCopyInIntegerArg(3, FALSE, &waitForImage); // Special case waitForImage == 4? This would ask to call into the capture driver, but // not wait for any image to arrive and not return any information. This is only useful // on OS/X and Windows when using the capture engine for video recording to harddisk. In // that case we are not interested at all in the captured live video, we just want it to // get written to harddisk in the background. To keep the video encoder going, we need to // call its SGIdle() routine and waitForImage==4 does just that, call SGIdle(). if (waitForImage == 4) { // Perform the null-call to the capture engine, ie a SGIdle() on OS/X and Windows: PsychGetTextureFromCapture(windowRecord, capturehandle, 4, 0.0, NULL, NULL, NULL, NULL); // Done. Nothing to return... return(PsychError_none); } // Get the optional textureRecord for the optional texture handle. If the calling script // provides the texture handle of an existing Psychtoolbox texture that has a matching // format, then that texture is recycled by overwriting its previous content with the // image data from the new captured image. This can save some overhead for texture destruction // and recreation. While this is probably not noticeable on mid- to high-end gfx cards with // rectangle texture support, it can provide a significant speedup on low-end gfx cards with // only power-of-two texture support. textureRecord = NULL; if ((PsychGetNumInputArgs()>=4) && PsychIsWindowIndexArg(4)) PsychAllocInWindowRecordArg(4, FALSE, &textureRecord); // Get the optional specialmode flag: PsychCopyInIntegerArg(5, FALSE, &specialmode); // Set a 10 second maximum timeout for waiting for new frames: PsychGetAdjustedPrecisionTimerSeconds(&timeout); timeout+=10; while (rc==-1) { // We pass a checkForImage value of 2 if waitForImage>0. This way we can signal if we are in polling or blocking mode. // With the libdc1394 engine this allows to do a real blocking wait in the driver -- much more efficient than the spin-waiting approach! rc = PsychGetTextureFromCapture(windowRecord, capturehandle, ((waitForImage>0 && waitForImage<3) ? 2 : 1), 0.0, NULL, &presentation_timestamp, NULL, &rawCaptureBuffer); PsychGetAdjustedPrecisionTimerSeconds(&tnow); if (rc==-2 || (tnow > timeout)) { // No image available and there won't be any in the future, because capture has been stopped or there is a timeout: if (tnow > timeout) printf("PTB-WARNING: In Screen('GetCapturedImage') timed out waiting for a new frame. No video data in over 10 seconds!\n"); // No new texture available: Return a negative handle: PsychCopyOutDoubleArg(1, TRUE, -1); // ...and an invalid timestamp: PsychCopyOutDoubleArg(2, FALSE, -1); PsychCopyOutDoubleArg(3, FALSE, 0); PsychCopyOutDoubleArg(4, FALSE, 0); // Ready! return(PsychError_none); } else if (rc==-1 && (waitForImage == 0 || waitForImage == 3)) { // We should just poll once and no new texture available: Return a null-handle: PsychCopyOutDoubleArg(1, TRUE, 0); // ...and the current timestamp: PsychCopyOutDoubleArg(2, FALSE, presentation_timestamp); PsychCopyOutDoubleArg(3, FALSE, 0); PsychCopyOutDoubleArg(4, FALSE, 0); // Ready! return(PsychError_none); } else if (rc==-1 && waitForImage != 0) { // No new texture available yet. Just sleep a bit and then retry... PsychYieldIntervalSeconds(0.002); } } // rc == 0 --> New image available: Go ahead... if (waitForImage!=2 && waitForImage!=3) { // Ok, we need a texture for the image. Did script provide an old one for recycling? if (textureRecord) { // Old texture provided for reuse? Some basic sanity check: Everything else is // up to the lower level PsychGetTextureFromCapture() routine. if(!PsychIsOffscreenWindow(textureRecord)) { PsychErrorExitMsg(PsychError_user, "GetCapturedImage provided with something else than a texture as fourth call parameter."); } } else { // No old texture provided: Create a new texture record: PsychCreateWindowRecord(&textureRecord); // Set mode to 'Texture': textureRecord->windowType=kPsychTexture; // We need to assign the screen number of the onscreen-window. textureRecord->screenNumber=windowRecord->screenNumber; // It defaults to a 32 bit texture for captured images. On Linux, this will be overriden, // if optimized formats exist for our purpose: textureRecord->depth=32; textureRecord->nrchannels = 4; // Create default rectangle which describes the dimensions of the image. Will be overwritten // later on. PsychMakeRect(rect, 0, 0, 10, 10); PsychCopyRect(textureRecord->rect, rect); // Other setup stuff: textureRecord->textureMemorySizeBytes= 0; textureRecord->textureMemory=NULL; // Assign parent window and copy its inheritable properties: PsychAssignParentWindow(textureRecord, windowRecord); // Set textureNumber to zero, which means "Not cached, do not recycle" // Todo: Texture recycling like in PsychMovieSupport for higher efficiency! textureRecord->textureNumber = 0; } // Power-of-two texture requested? if (specialmode & 0x01) { // Yes. Spec it: textureRecord->texturetarget = GL_TEXTURE_2D; } } else { // Just want to return summed_intensity and timestamp, not real texture... textureRecord = NULL; } // Default to no calculation of summed image intensity: tsummed = NULL; if ((PsychGetNumOutputArgs() > 3) && !(specialmode & 0x2)) { // Return sum of pixel intensities for all channels of this image: Need to // assign the output pointer for this to happen: tsummed = &summed_intensity; } // Try to fetch an image from the capture object and return it as texture: targetmatrixptr = NULL; // Shall we return a Matlab matrix? if ((PsychGetNumOutputArgs() > 3) && (specialmode & 0x2)) { // We shall return a matrix with raw image data. Allocate a uint8 matrix // of sufficient size: PsychAllocOutUnsignedByteMatArg(4, TRUE, rawCaptureBuffer.depth, rawCaptureBuffer.w, rawCaptureBuffer.h, &targetmatrixptr); tsummed = NULL; } // Shall we return data into preallocated memory buffer? if (specialmode & 0x4) { // Copy in memory address (which itself is encoded in a double value): PsychCopyInDoubleArg(6, TRUE, &targetmemptr); targetmatrixptr = (psych_uint8*) PsychDoubleToPtr(targetmemptr); } if (targetmatrixptr == NULL) { // Standard fetch of a texture and its timestamp: rc = PsychGetTextureFromCapture(windowRecord, capturehandle, 0, 0.0, textureRecord, &presentation_timestamp, tsummed, NULL); } else { // Fetch of a memory raw image buffer + timestamp + possibly a texture: rawCaptureBuffer.data = (void*) targetmatrixptr; rc = PsychGetTextureFromCapture(windowRecord, capturehandle, 0, 0.0, textureRecord, &presentation_timestamp, tsummed, &rawCaptureBuffer); } if (tsummed) { // Return sum of pixel intensities for all channels of this image: PsychCopyOutDoubleArg(4, FALSE, summed_intensity); } // Real texture requested? if (textureRecord) { // Texture ready for consumption. // Assign GLSL filter-/lookup-shaders if needed: usefloatformat is always == 0 as // our current capture engine implementations only return 8 bpc fixed textures. // The 'userRequest' flag is set if specialmode flag is set to 8. PsychAssignHighPrecisionTextureShaders(textureRecord, windowRecord, 0, (specialmode & 8) ? 1 : 0); // specialmode setting 16? Disable auto-mipmap generation: if (specialmode & 16) textureRecord->specialflags |= kPsychDontAutoGenMipMaps; // Mark it valid and return handle to userspace: PsychSetWindowRecordValid(textureRecord); PsychCopyOutDoubleArg(1, TRUE, textureRecord->windowIndex); } else { PsychCopyOutDoubleArg(1, TRUE, 0); } // Return presentation timestamp for this image: PsychCopyOutDoubleArg(2, FALSE, presentation_timestamp); // Return count of pending frames in buffers or of dropped frames: PsychCopyOutDoubleArg(3, FALSE, (double) rc); // Ready! return(PsychError_none); }
void moglcopybuffertomatrix(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { int type; size_t dims; mwSize outdims; GLenum mattype; GLfloat* dst; // Retrieve ptr to membuffer, encoded as double and convert it into a void* void* src = PsychDoubleToPtr((GLdouble) mxGetScalar(prhs[0])); // Retrieve size of buffer pointed to by src: size_t n = PsychGetBufferSizeForPtr(src); // Retrieve max number of bytes to copy: size_t nmax = (size_t) mxGetScalar(prhs[2]); if (nmax < n) n = nmax; // Retrieve type of matrix to create: mattype = (GLenum) mxGetScalar(prhs[1]); switch(mattype) { case GL_DOUBLE: type = mxDOUBLE_CLASS; dims = n / sizeof(double); if (dims * sizeof(double) < n) dims++; break; case GL_FLOAT: type = mxSINGLE_CLASS; dims = n / sizeof(float); if (dims * sizeof(float) < n) dims++; break; case GL_UNSIGNED_INT: type = mxUINT32_CLASS; dims = n / sizeof(unsigned int); if (dims * sizeof(unsigned int) < n) dims++; break; case GL_UNSIGNED_BYTE: type = mxUINT8_CLASS; dims = n / sizeof(unsigned char); if (dims * sizeof(unsigned char) < n) dims++; break; default: type = 0; mexErrMsgTxt("MOGL-ERROR: Unknown matrix type requested in moglgetbuffer()! Ignored."); } if ((sizeof(outdims) < sizeof(dims)) && (dims > INT_MAX)) { mexErrMsgTxt("MOGL-ERROR: In moglgetbuffer(): Returned matrix is too big (more than 2^31 - 1 elements) for your version of Matlab or Octave! Aborted."); } // Allocate the beast: outdims = (mwSize) dims; plhs[0] = mxCreateNumericArray(1, &outdims, type, mxREAL); // Retrieve pointer to output matrix: dst = (GLfloat*) mxGetData(plhs[0]); // Do the copy: memcpy(dst, src, n); }