mirror of
https://github.com/encounter/SDL.git
synced 2025-06-01 20:21:22 +00:00
only geniconv/iconv.h (was from LGPL libiconv) is replaced with a generic minimal iconv.h based on public knowledge.
349 lines
9.7 KiB
C
349 lines
9.7 KiB
C
/*
|
|
Simple DirectMedia Layer
|
|
Copyright (C) 1997-2016 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;
|
|
}
|