PsychError SCREENTexturizeOffscreenWindows(void) { PsychWindowRecordType **windowRecordArray; int i, numWindows; //all subfunctions should have these two lines. PsychPushHelp(useString, synopsisString, seeAlsoString); if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);}; //check for superfluous or missing arguments PsychErrorExit(PsychCapNumInputArgs(0)); PsychErrorExit(PsychRequireNumInputArgs(0)); PsychCreateVolatileWindowRecordPointerList(&numWindows, &windowRecordArray); for(i=0;i<numWindows;i++){ if(PsychIsOffscreenWindow(windowRecordArray[i])){ PsychUpdateTargetWindowFromTargetDisplay(windowRecordArray[i]); PsychAllocateTexture(windowRecordArray[i]); PsychBindTexture(windowRecordArray[i]); PsychUpdateTexture(windowRecordArray[i]); } } PsychDestroyVolatileWindowRecordPointerList(windowRecordArray); return(PsychError_none); }
/* * void PsychQTExitMovies() - Shutdown handler. * * This routine is called by Screen('CloseAll') and on clear Screen time to * do final cleanup. It deletes all Quicktime textures and releases all Quicktime * movie objects. * */ void PsychQTExitMovies(void) { PsychWindowRecordType **windowRecordArray; int i, numWindows; // Release all Quicktime related OpenGL textures: PsychCreateVolatileWindowRecordPointerList(&numWindows, &windowRecordArray); for(i=0; i<numWindows; i++) { // Delete all Quicktime textures: if ((windowRecordArray[i]->windowType == kPsychTexture) && (windowRecordArray[i]->targetSpecific.QuickTimeGLTexture !=NULL)) { PsychCloseWindow(windowRecordArray[i]); } } PsychDestroyVolatileWindowRecordPointerList(windowRecordArray); // Release all movies: PsychQTDeleteAllMovies(); // Shutdown Quicktime toolbox: We skip this, because according to Apple its not necessary, // and for some reason it reliably hangs Matlab, so one has to force-quit it :-( // Don't do this: ExitMovies(); #if PSYCH_SYSTEM == PSYCH_WINDOWS // Shutdown Quicktime core system: ExitMovies(); // Shutdown Quicktime for Windows compatibility layer: TerminateQTML(); #endif return; }
void PsychFindScreenWindowFromScreenNumber(int screenNumber, PsychWindowRecordType **winRec) { int i, numWindows; PsychWindowRecordType **windowArray; *winRec=NULL; if(screenNumber==kPsychUnaffiliatedWindow) return; PsychCreateVolatileWindowRecordPointerList(&numWindows, &windowArray); for(i=0;i<numWindows;i++){ if(PsychIsOnscreenWindow(windowArray[i])){ if(windowArray[i]->screenNumber==screenNumber){ *winRec=windowArray[i]; break; } } } PsychDestroyVolatileWindowRecordPointerList(windowArray); }
PsychError SCREENWindows(void) { PsychWindowRecordType **windowRecordArray; int i,numWindows; double *windowPointers; //all sub functions should have these two lines PsychPushHelp(useString, synopsisString, seeAlsoString); if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);}; PsychErrorExit(PsychCapNumOutputArgs(1)); PsychErrorExit(PsychCapNumInputArgs(0)); PsychCreateVolatileWindowRecordPointerList(&numWindows, &windowRecordArray); PsychAllocOutDoubleMatArg(1, FALSE, 1, numWindows, 0, &windowPointers); for(i=0;i<numWindows;i++) windowPointers[i]=windowRecordArray[i]->windowIndex; PsychDestroyVolatileWindowRecordPointerList(windowRecordArray); return(PsychError_none); }
/* * void PsychGSExitMovies() - Shutdown handler. * * This routine is called by Screen('CloseAll') and on clear Screen time to * do final cleanup. It deletes all textures and releases all movie objects. * */ void PsychGSExitMovies(void) { PsychWindowRecordType **windowRecordArray; int i, numWindows; // Release all Quicktime related OpenGL textures: PsychCreateVolatileWindowRecordPointerList(&numWindows, &windowRecordArray); for(i=0; i<numWindows; i++) { // Delete all Quicktime textures: if ((windowRecordArray[i]->windowType == kPsychTexture) && (windowRecordArray[i]->targetSpecific.QuickTimeGLTexture !=NULL)) { PsychCloseWindow(windowRecordArray[i]); } } PsychDestroyVolatileWindowRecordPointerList(windowRecordArray); // Release all movies: PsychGSDeleteAllMovies(); firsttime = TRUE; return; }
PsychError SCREENPreloadTextures(void) { PsychWindowRecordType *windowRecord, *texwin; psych_bool isArgThere; int *texhandles; PsychWindowRecordType **windowRecordArray; int i, n, numWindows, myhandle; double *success; psych_bool* residency; GLuint* texids; GLboolean* texresident; psych_bool failed = false; GLclampf maxprio = 1.0f; GLenum target; //all sub functions should have these two lines PsychPushHelp(useString, synopsisString,seeAlsoString); if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);}; //check for superfluous arguments PsychErrorExit(PsychCapNumInputArgs(2)); //The maximum number of inputs PsychErrorExit(PsychRequireNumInputArgs(1)); //The minimum 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(1, kPsychArgRequired, &windowRecord); // Get optional texids vector: isArgThere = PsychIsArgPresent(PsychArgIn, 2); PsychAllocInIntegerListArg(2, FALSE, &n, &texhandles); if (n < 1) isArgThere=FALSE; // Enable this windowRecords framebuffer as current drawingtarget: PsychSetDrawingTarget(windowRecord); // Disable shader: PsychSetShader(windowRecord, 0); glDisable(GL_TEXTURE_2D); // Fetch global texturing mode: target=PsychGetTextureTarget(windowRecord); glEnable(target); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor4f(0, 0, 0, 0); // Setup identity modelview matrix: glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); PsychCreateVolatileWindowRecordPointerList(&numWindows, &windowRecordArray); // Process vector of all texids for all requested textures: if (!isArgThere) { // No handles provided: In this case, we preload all textures: n=0; for(i=0; i<numWindows; i++) { if (windowRecordArray[i]->windowType==kPsychTexture) { n++; // Prioritize this texture: glPrioritizeTextures(1, (GLuint*) &(windowRecordArray[i]->textureNumber), &maxprio); // Bind this texture: glBindTexture(target, windowRecordArray[i]->textureNumber); // Render a single textured point, thereby enforcing a texture upload: glBegin(GL_QUADS); glTexCoord2f(0,0); glVertex2i(10,10); glTexCoord2f(0,1); glVertex2i(10,11); glTexCoord2f(1,1); glVertex2i(11,11); glTexCoord2f(1,0); glVertex2i(11,10); glEnd(); } } texids = (GLuint*) PsychMallocTemp(sizeof(GLuint) * n); texresident = (GLboolean*) PsychMallocTemp(sizeof(GLboolean) * n); n=0; for(i=0; i<numWindows; i++) { if (windowRecordArray[i]->windowType==kPsychTexture) { texids[n] = (GLuint) windowRecordArray[i]->textureNumber; n++; } } } else { // Vector with texture handles provided: Just preload them. texids = (GLuint*) PsychMallocTemp(sizeof(GLuint) * n); texresident = (GLboolean*) PsychMallocTemp(sizeof(GLboolean) * n); myhandle=0; for (i=0; i<n; i++) { myhandle = texhandles[i]; texwin = NULL; if (IsWindowIndex(myhandle)) FindWindowRecord(myhandle, &texwin); if (texwin && texwin->windowType==kPsychTexture) { // Prioritize this texture: glPrioritizeTextures(1, (GLuint*) &(texwin->textureNumber), &maxprio); // Bind this texture: glBindTexture(target, texwin->textureNumber); // Render a single textured point, thereby enforcing a texture upload: glBegin(GL_QUADS); glTexCoord2f(0,0); glVertex2i(10,10); glTexCoord2f(0,1); glVertex2i(10,11); glTexCoord2f(1,1); glVertex2i(11,11); glTexCoord2f(1,0); glVertex2i(11,10); glEnd(); texids[i] = (GLuint) texwin->textureNumber; } else { // This handle is invalid or at least no texture handle: printf("PTB-ERROR! Screen('PreloadTextures'): Entry %i of texture handle vector (handle %i) is not a texture handle!\n", i, myhandle); failed = true; } } } // Restore old matrix from backup copy, undoing the global translation: glPopMatrix(); // Disable texture engine: glDisable(GL_TEXTURE_2D); glDisable(target); // Wait for prefetch completion: glFinish(); // We don't need these anymore: PsychDestroyVolatileWindowRecordPointerList(windowRecordArray); if (failed) { PsychErrorExitMsg(PsychError_user, "At least one texture handle in texids-vector was invalid! Aborted."); } // Query residency state of all preloaded textures: success = NULL; PsychAllocOutDoubleArg(1, FALSE, &success); *success = (double) glAreTexturesResident(n, texids, texresident); // Sync pipe again, just to be safe... glFinish(); // Count them and copy them into output vector: PsychAllocOutBooleanMatArg(2, FALSE, n, 1, 1, &residency); for (i=0; i<n; i++) { residency[i] = (psych_bool) ((*success) ? TRUE : texresident[i]); } PsychTestForGLErrors(); // Done. Our PsychMallocTemp'ed arrays will be auto-released... return(PsychError_none); }
PsychError SCREENClose(void) { PsychWindowRecordType *windowRecord; int screenNumber; PsychWindowRecordType **windowRecordArray; int i, numWindows; windowRecord=NULL; //all subfunctions should have these two lines. PsychPushHelp(useString, synopsisString, seeAlsoString); if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);}; PsychErrorExit(PsychCapNumInputArgs(1)); //The maximum number of inputs PsychErrorExit(PsychRequireNumInputArgs(0)); //The minimum required number of inputs PsychErrorExit(PsychCapNumOutputArgs(0)); //The maximum number of outputs //Get the window record or exit with an error if the windex was bogus. // PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord); PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, kPsychArgOptional, &windowRecord); // Window handle of a specific window provided? if (windowRecord==NULL) { // No window handle provided: In this case, we close/destroy all textures: PsychCreateVolatileWindowRecordPointerList(&numWindows, &windowRecordArray); for(i=0;i<numWindows;i++) { if (windowRecordArray[i]->windowType==kPsychTexture) PsychCloseWindow(windowRecordArray[i]); } PsychDestroyVolatileWindowRecordPointerList(windowRecordArray); return(PsychError_none); } // Window handle of a specific window or texture provided: Close it... if(PsychIsLastOnscreenWindow(windowRecord)){ screenNumber=windowRecord->screenNumber; PsychCloseWindow(windowRecord); PsychReleaseScreen(screenNumber); }else PsychCloseWindow(windowRecord); return(PsychError_none); }
// Implement closing of all onscreen- and offscreen windows, release of all captured displays, // releasing of all internal textures and memory buffers, stopping of internal helper threads, // etc.... // This routine is normally called by SCREENCloseAll, but can be also called by the exit-handler, // and diverse error-handlers for cleanup. void ScreenCloseAllWindows(void) { PsychWindowRecordType **windowRecordArray; int i, numWindows, numScreens; static unsigned int recursionLevel = 0; // Recursive self-call? if (recursionLevel > 0) { // Ohoh: We are recursively calling ourselves, probably due to some // error condition triggered during our execution. This is bad, we need // to break the infinite recursion. How? We output a recursion warning, // then return as no-op: printf("PTB-ERROR: Error during error handling! ScreenCloseAllWindows() called recursively! Trying to break out of this vicious cycle...\n"); printf("PTB-ERROR: Maybe it is a good idea to exit and restart Matlab/Octave.\n"); // Skip to the release screen routine and hope for the best: goto critical_abort; } recursionLevel++; // Cold-Reset the drawing target: PsychColdResetDrawingTarget(); // Reset the "userspaceGL" flag which tells PTB that userspace GL rendering was active // due to Screen('BeginOpenGL') command. PsychSetUserspaceGLFlag(FALSE); // Check for stale texture ressources: PsychRessourceCheckAndReminder(TRUE); // Shutdown Quicktime subsystems if active: PsychExitMovieWriting(); PsychExitMovies(); PsychExitVideoCapture(); // Close the windows: We do it reverse (descending) order so textures get closed // before the onscreen windows. In theory this shouldn't matter, but in practice, // more stress on the PsychCloseWindow() path. If we have bugs there, chances are // higher they get exposed this way, which long-term is a good thing(TM). PsychCreateVolatileWindowRecordPointerList(&numWindows, &windowRecordArray); for(i = numWindows - 1; i >= 0; i--) { if (PsychPrefStateGet_Verbosity()>5) { printf("PTB-DEBUG: In ScreenCloseAllWindows(): Destroying window %i\n", i); fflush(NULL); } PsychCloseWindow(windowRecordArray[i]); } PsychDestroyVolatileWindowRecordPointerList(windowRecordArray); critical_abort: // Release all captured displays, unhide the cursor on each of them: numScreens=PsychGetNumDisplays(); for(i=0;i<numScreens;i++){ if(PsychIsScreenCaptured(i)) { PsychRestoreScreenSettings(i); PsychReleaseScreen(i); } PsychShowCursor(i, -1); } recursionLevel--; return; }
// Callback handler for Window manager: Handles some events LONG FAR PASCAL WndProc(HWND hWnd, unsigned uMsg, unsigned wParam, LONG lParam) { static PAINTSTRUCT ps; PsychWindowRecordType **windowRecordArray; int i, numWindows; // What event happened? switch(uMsg) { case WM_SYSCOMMAND: // System command received: We intercept system commands that would start // the screensaver or put the display into powersaving sleep-mode: switch(wParam) { case SC_SCREENSAVE: case SC_MONITORPOWER: return(0); } break; case WM_LBUTTONDOWN: // Left mouse button depressed: mousebutton_l = TRUE; break; case WM_LBUTTONUP: // Left mouse button released: mousebutton_l = FALSE; break; case WM_MBUTTONDOWN: // Middle mouse button depressed: mousebutton_m = TRUE; break; case WM_MBUTTONUP: // Middle mouse button released: mousebutton_m = FALSE; break; case WM_RBUTTONDOWN: // Right mouse button depressed: mousebutton_r = TRUE; break; case WM_RBUTTONUP: // Right mouse button released: mousebutton_r = FALSE; break; case WM_PAINT: // Repaint event: This happens if a previously covered non-fullscreen window // got uncovered, so part of it needs to be redrawn. PTB's rendering model // doesn't have a concept of redrawing a stimulus. As this is mostly useful // for debugging, we just do a double doublebuffer swap in the hope that this // will restore the frontbuffer... BeginPaint(hWnd, &ps); EndPaint(hWnd, &ps); // Scan the list of windows to find onscreen window with handle hWnd: PsychCreateVolatileWindowRecordPointerList(&numWindows, &windowRecordArray); for(i = 0; i < numWindows; i++) { if (PsychIsOnscreenWindow(windowRecordArray[i]) && windowRecordArray[i]->targetSpecific.windowHandle == hWnd && windowRecordArray[i]->stereomode == 0) { // This is it! Initiate bufferswap twice: PsychOSFlipWindowBuffers(windowRecordArray[i]); PsychOSFlipWindowBuffers(windowRecordArray[i]); } } PsychDestroyVolatileWindowRecordPointerList(windowRecordArray); // Done. return 0; case WM_SIZE: // Window resize event: Only happens in debug-mode (non-fullscreen). // We resize the viewport accordingly and then trigger a repaint-op. glViewport(0, 0, LOWORD(lParam), HIWORD(lParam)); PostMessage(hWnd, WM_PAINT, 0, 0); // printf("\nPTB-INFO: Onscreen window resized to: %i x %i.\n", (int) LOWORD(lParam), (int) HIWORD(lParam)); return 0; case WM_CLOSE: // WM_CLOSE falls through to WM_CHAR and emulates an Abort-key press. // -> Manually closing an onscreen window does the same as pressing the Abort-key. wParam='@'; case WM_CHAR: // Character received. We only care about one key, the '@' key. // Pressing '@' will immediately close all onscreen windows, show // the cursor and such. It is the emergency stop key. if (wParam=='@') { // Emergency shutdown: printf("\nPTB-INFO: Master-Abort key '@' pressed by user.\n"); printf("PTB-INFO: Enforcing script abortion and restoring desktop by executing Screen('CloseAll') now!\n"); printf("PTB-INFO: Please ignore the false error message (INTERNAL PSYCHTOOLBOX ERROR) caused by this...\n"); ScreenCloseAllWindows(); return(0); } break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); }