| /* |
| Simple DirectMedia Layer |
| Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> |
| |
| This software is provided 'as-is', without any express or implied |
| warranty. In no event will the authors be held liable for any damages |
| arising from the use of this software. |
| |
| Permission is granted to anyone to use this software for any purpose, |
| including commercial applications, and to alter it and redistribute it |
| freely, subject to the following restrictions: |
| |
| 1. The origin of this software must not be misrepresented; you must not |
| claim that you wrote the original software. If you use this software |
| in a product, an acknowledgment in the product documentation would be |
| appreciated but is not required. |
| 2. Altered source versions must be plainly marked as such, and must not be |
| misrepresented as being the original software. |
| 3. This notice may not be removed or altered from any source distribution. |
| */ |
| #include "../../SDL_internal.h" |
| #include "../SDL_sysvideo.h" |
| #define INCL_WIN |
| #define INCL_GPI |
| #include <os2.h> |
| #define _MEERROR_H_ |
| #include <mmioos2.h> |
| #include <os2me.h> |
| #define INCL_MM_OS2 |
| #include <dive.h> |
| #include <fourcc.h> |
| #include "SDL_os2output.h" |
| |
| typedef struct _VODATA { |
| HDIVE hDive; |
| PVOID pBuffer; |
| ULONG ulDIVEBufNum; |
| FOURCC fccColorEncoding; |
| ULONG ulWidth; |
| ULONG ulHeight; |
| BOOL fBlitterReady; |
| } VODATA; |
| |
| static BOOL voQueryInfo(PVIDEOOUTPUTINFO pInfo); |
| static PVODATA voOpen(); |
| static VOID voClose(PVODATA pVOData); |
| static BOOL voSetVisibleRegion(PVODATA pVOData, HWND hwnd, |
| SDL_DisplayMode *pSDLDisplayMode, |
| HRGN hrgnShape, BOOL fVisible); |
| static PVOID voVideoBufAlloc(PVODATA pVOData, ULONG ulWidth, ULONG ulHeight, |
| ULONG ulBPP, ULONG fccColorEncoding, |
| PULONG pulScanLineSize); |
| static VOID voVideoBufFree(PVODATA pVOData); |
| static BOOL voUpdate(PVODATA pVOData, HWND hwnd, SDL_Rect *pSDLRects, |
| ULONG cSDLRects); |
| |
| OS2VIDEOOUTPUT voDive = { |
| voQueryInfo, |
| voOpen, |
| voClose, |
| voSetVisibleRegion, |
| voVideoBufAlloc, |
| voVideoBufFree, |
| voUpdate |
| }; |
| |
| |
| static BOOL voQueryInfo(PVIDEOOUTPUTINFO pInfo) |
| { |
| DIVE_CAPS sDiveCaps = { 0 }; |
| FOURCC fccFormats[100] = { 0 }; |
| |
| // Query information about display hardware from DIVE. |
| |
| sDiveCaps.pFormatData = fccFormats; |
| sDiveCaps.ulFormatLength = 100; |
| sDiveCaps.ulStructLen = sizeof(DIVE_CAPS); |
| |
| if ( DiveQueryCaps( &sDiveCaps, DIVE_BUFFER_SCREEN ) ) |
| { |
| debug( "DiveQueryCaps() failed." ); |
| return FALSE; |
| } |
| |
| if ( sDiveCaps.ulDepth < 8 ) |
| { |
| debug( "Not enough screen colors to run DIVE. " |
| "Must be at least 256 colors." ); |
| return FALSE; |
| } |
| |
| pInfo->ulBPP = sDiveCaps.ulDepth; |
| pInfo->fccColorEncoding = sDiveCaps.fccColorEncoding; |
| pInfo->ulScanLineSize = sDiveCaps.ulScanLineBytes; |
| pInfo->ulHorizResolution = sDiveCaps.ulHorizontalResolution; |
| pInfo->ulVertResolution = sDiveCaps.ulVerticalResolution; |
| |
| return TRUE; |
| } |
| |
| PVODATA voOpen() |
| { |
| PVODATA pVOData = SDL_calloc( 1, sizeof(VODATA) ); |
| |
| if ( pVOData == NULL ) |
| { |
| SDL_OutOfMemory(); |
| return NULL; |
| } |
| |
| if ( DiveOpen( &pVOData->hDive, FALSE, NULL ) != DIVE_SUCCESS ) |
| { |
| SDL_free( pVOData ); |
| SDL_SetError( "DIVE: A display engine instance open failed" ); |
| return NULL; |
| } |
| |
| return pVOData; |
| } |
| |
| static VOID voClose(PVODATA pVOData) |
| { |
| voVideoBufFree( pVOData ); |
| DiveClose( pVOData->hDive ); |
| SDL_free( pVOData ); |
| } |
| |
| static BOOL voSetVisibleRegion(PVODATA pVOData, HWND hwnd, |
| SDL_DisplayMode *pSDLDisplayMode, |
| HRGN hrgnShape, BOOL fVisible) |
| { |
| HPS hps; |
| HRGN hrgn; |
| RGNRECT rgnCtl; |
| PRECTL prectl = NULL; |
| ULONG ulRC; |
| |
| if ( !fVisible ) |
| { |
| if ( pVOData->fBlitterReady ) |
| { |
| pVOData->fBlitterReady = FALSE; |
| DiveSetupBlitter( pVOData->hDive, 0 ); |
| debug( "DIVE blitter is tuned off" ); |
| } |
| return TRUE; |
| } |
| |
| // Query visible rectangles |
| |
| hps = WinGetPS( hwnd ); |
| hrgn = GpiCreateRegion( hps, 0, NULL ); |
| if ( hrgn == NULLHANDLE ) |
| { |
| WinReleasePS( hps ); |
| SDL_SetError( "GpiCreateRegion() failed" ); |
| } |
| else |
| { |
| WinQueryVisibleRegion( hwnd, hrgn ); |
| if ( hrgnShape != NULLHANDLE ) |
| GpiCombineRegion( hps, hrgn, hrgn, hrgnShape, CRGN_AND ); |
| |
| rgnCtl.ircStart = 1; |
| rgnCtl.crc = 0; |
| rgnCtl.ulDirection = 1; |
| GpiQueryRegionRects( hps, hrgn, NULL, &rgnCtl, NULL ); |
| if ( rgnCtl.crcReturned != 0 ) |
| { |
| prectl = SDL_malloc( rgnCtl.crcReturned * sizeof(RECTL) ); |
| if ( prectl != NULL ) |
| { |
| rgnCtl.ircStart = 1; |
| rgnCtl.crc = rgnCtl.crcReturned; |
| rgnCtl.ulDirection = 1; |
| GpiQueryRegionRects( hps, hrgn, NULL, &rgnCtl, prectl ); |
| } |
| else |
| SDL_OutOfMemory(); |
| } |
| GpiDestroyRegion( hps, hrgn ); |
| WinReleasePS( hps ); |
| |
| if ( prectl != NULL ) |
| { |
| // Setup DIVE blitter. |
| SETUP_BLITTER sSetupBlitter; |
| SWP swp; |
| POINTL pointl = { 0 }; |
| |
| WinQueryWindowPos( hwnd, &swp ); |
| WinMapWindowPoints( hwnd, HWND_DESKTOP, &pointl, 1 ); |
| |
| sSetupBlitter.ulStructLen = sizeof(SETUP_BLITTER); |
| sSetupBlitter.fccSrcColorFormat = pVOData->fccColorEncoding; |
| sSetupBlitter.fInvert = FALSE; |
| sSetupBlitter.ulSrcWidth = pVOData->ulWidth; |
| sSetupBlitter.ulSrcHeight = pVOData->ulHeight; |
| sSetupBlitter.ulSrcPosX = 0; |
| sSetupBlitter.ulSrcPosY = 0; |
| sSetupBlitter.ulDitherType = 0; |
| sSetupBlitter.fccDstColorFormat = FOURCC_SCRN; |
| sSetupBlitter.ulDstWidth = swp.cx; |
| sSetupBlitter.ulDstHeight = swp.cy; |
| sSetupBlitter.lDstPosX = 0; |
| sSetupBlitter.lDstPosY = 0; |
| sSetupBlitter.lScreenPosX = pointl.x; |
| sSetupBlitter.lScreenPosY = pointl.y; |
| |
| sSetupBlitter.ulNumDstRects = rgnCtl.crcReturned; |
| sSetupBlitter.pVisDstRects = prectl; |
| |
| ulRC = DiveSetupBlitter( pVOData->hDive, &sSetupBlitter ); |
| SDL_free( prectl ); |
| |
| if ( ulRC == DIVE_SUCCESS ) |
| { |
| pVOData->fBlitterReady = TRUE; |
| WinInvalidateRect( hwnd, NULL, TRUE ); |
| debug( "DIVE blitter is ready now." ); |
| return TRUE; |
| } |
| |
| SDL_SetError( "DiveSetupBlitter(), rc = 0x%X", ulRC ); |
| } // if ( prectl != NULL ) |
| } // if ( hrgn == NULLHANDLE ) else |
| |
| pVOData->fBlitterReady = FALSE; |
| DiveSetupBlitter( pVOData->hDive, 0 ); |
| return FALSE; |
| } |
| |
| static PVOID voVideoBufAlloc(PVODATA pVOData, ULONG ulWidth, ULONG ulHeight, |
| ULONG ulBPP, FOURCC fccColorEncoding, |
| PULONG pulScanLineSize) |
| { |
| ULONG ulRC; |
| ULONG ulScanLineSize = ulWidth * (ulBPP >> 3); |
| |
| // Destroy previous buffer. |
| voVideoBufFree( pVOData ); |
| |
| if ( ( ulWidth == 0 ) || ( ulHeight == 0 ) || ( ulBPP == 0 ) ) |
| return NULL; |
| |
| // Bytes per line. |
| ulScanLineSize = ( ulScanLineSize + 3 ) & ~3; /* 4-byte aligning */ |
| *pulScanLineSize = ulScanLineSize; |
| |
| ulRC = DosAllocMem( &pVOData->pBuffer, |
| (ulHeight * ulScanLineSize) + sizeof(ULONG), |
| PAG_COMMIT | PAG_EXECUTE | PAG_READ | PAG_WRITE ); |
| if ( ulRC != NO_ERROR ) |
| { |
| debug( "DosAllocMem(), rc = %u", ulRC ); |
| return NULL; |
| } |
| |
| ulRC = DiveAllocImageBuffer( pVOData->hDive, &pVOData->ulDIVEBufNum, |
| fccColorEncoding, ulWidth, ulHeight, |
| ulScanLineSize, pVOData->pBuffer ); |
| if ( ulRC != DIVE_SUCCESS ) |
| { |
| debug( "DiveAllocImageBuffer(), rc = 0x%X", ulRC ); |
| DosFreeMem( pVOData->pBuffer ); |
| pVOData->pBuffer = NULL; |
| pVOData->ulDIVEBufNum = 0; |
| return NULL; |
| } |
| |
| pVOData->fccColorEncoding = fccColorEncoding; |
| pVOData->ulWidth = ulWidth; |
| pVOData->ulHeight = ulHeight; |
| |
| debug( "buffer: 0x%P, DIVE buffer number: %u", |
| pVOData->pBuffer, pVOData->ulDIVEBufNum ); |
| |
| return pVOData->pBuffer; |
| } |
| |
| static VOID voVideoBufFree(PVODATA pVOData) |
| { |
| ULONG ulRC; |
| |
| if ( pVOData->ulDIVEBufNum != 0 ) |
| { |
| ulRC = DiveFreeImageBuffer( pVOData->hDive, pVOData->ulDIVEBufNum ); |
| if ( ulRC != DIVE_SUCCESS ) |
| debug( "DiveFreeImageBuffer(,%u), rc = %u", pVOData->ulDIVEBufNum, ulRC ); |
| else |
| debug( "DIVE buffer %u destroyed", pVOData->ulDIVEBufNum ); |
| |
| pVOData->ulDIVEBufNum = 0; |
| } |
| |
| if ( pVOData->pBuffer != NULL ) |
| { |
| ulRC = DosFreeMem( pVOData->pBuffer ); |
| if ( ulRC != NO_ERROR ) |
| debug( "DosFreeMem(), rc = %u", ulRC ); |
| |
| pVOData->pBuffer = NULL; |
| } |
| } |
| |
| static BOOL voUpdate(PVODATA pVOData, HWND hwnd, SDL_Rect *pSDLRects, |
| ULONG cSDLRects) |
| { |
| ULONG ulRC; |
| |
| if ( !pVOData->fBlitterReady || ( pVOData->ulDIVEBufNum == 0 ) ) |
| { |
| debug( "DIVE blitter is not ready" ); |
| return FALSE; |
| } |
| |
| if ( pSDLRects != 0 ) |
| { |
| PBYTE pbLineMask; |
| |
| pbLineMask = SDL_stack_alloc( BYTE, pVOData->ulHeight ); |
| if ( pbLineMask == NULL ) |
| { |
| debug( "Not enough stack size" ); |
| return FALSE; |
| } |
| memset( pbLineMask, 0, pVOData->ulHeight ); |
| |
| for( ; ((LONG)cSDLRects) > 0; cSDLRects--, pSDLRects++ ) |
| memset( &pbLineMask[pSDLRects->y], 1, pSDLRects->h ); |
| |
| ulRC = DiveBlitImageLines( pVOData->hDive, pVOData->ulDIVEBufNum, |
| DIVE_BUFFER_SCREEN, pbLineMask ); |
| SDL_stack_free( pbLineMask ); |
| |
| if ( ulRC != DIVE_SUCCESS ) |
| debug( "DiveBlitImageLines(), rc = 0x%X", ulRC ); |
| } |
| else |
| { |
| ulRC = DiveBlitImage( pVOData->hDive, pVOData->ulDIVEBufNum, |
| DIVE_BUFFER_SCREEN ); |
| if ( ulRC != DIVE_SUCCESS ) |
| debug( "DiveBlitImage(), rc = 0x%X", ulRC ); |
| } |
| |
| return ulRC == DIVE_SUCCESS; |
| } |