mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
UTIL is never used, and JA2 is always used. assumption being we'll never make 1.13 for Wizardry 8. video2.h doesn't exist, which prevented me from deleting it.
2840 lines
72 KiB
C++
2840 lines
72 KiB
C++
#include "DirectDraw Calls.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "debug.h"
|
|
#include "video.h"
|
|
#include "himage.h"
|
|
#include "vsurface.h"
|
|
#include "vsurface_private.h"
|
|
#include "wcheck.h"
|
|
#include "vobject_blitters.h"
|
|
|
|
extern void SetClippingRect(SGPRect *clip);
|
|
extern void GetClippingRect(SGPRect *clip);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Video Surface SGP Module
|
|
//
|
|
// Second Revision: Dec 10, 1996, Andrew Emmons
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Defines
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// This define is sent to CreateList SGP function. It dynamically re-sizes if
|
|
// the list gets larger
|
|
//
|
|
|
|
#define DEFAULT_NUM_REGIONS 5
|
|
#define DEFAULT_VIDEO_SURFACE_LIST_SIZE 10
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LOCAL functions
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOLEAN UpdateBackupSurface( HVSURFACE hVSurface );
|
|
BOOLEAN ClipReleatedSrcAndDestRectangles( HVSURFACE hDestVSurface, HVSURFACE hSrcVSurface, RECT *DestRect, RECT *SrcRect );
|
|
BOOLEAN FillSurface( HVSURFACE hDestVSurface, blt_vs_fx *pBltFx );
|
|
BOOLEAN FillSurfaceRect( HVSURFACE hDestVSurface, blt_vs_fx *pBltFx );
|
|
BOOLEAN BltVSurfaceUsingDD( HVSURFACE hDestVSurface, HVSURFACE hSrcVSurface, UINT32 fBltFlags, INT32 iDestX, INT32 iDestY, RECT *SrcRect );
|
|
BOOLEAN BltVSurfaceUsingDDBlt( HVSURFACE hDestVSurface, HVSURFACE hSrcVSurface, UINT32 fBltFlags, INT32 iDestX, INT32 iDestY, RECT *SrcRect, RECT *DestRect );
|
|
BOOLEAN GetVSurfaceRect( HVSURFACE hVSurface, RECT *pRect);
|
|
|
|
void DeletePrimaryVideoSurfaces( );
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LOCAL global variables
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef struct VSURFACE_NODE
|
|
{
|
|
HVSURFACE hVSurface;
|
|
UINT32 uiIndex;
|
|
struct VSURFACE_NODE *next, *prev;
|
|
|
|
#ifdef SGP_VIDEO_DEBUGGING
|
|
STR8 pName;
|
|
STR8 pCode;
|
|
#endif
|
|
|
|
}VSURFACE_NODE;
|
|
|
|
VSURFACE_NODE *gpVSurfaceHead = NULL;
|
|
VSURFACE_NODE *gpVSurfaceTail = NULL;
|
|
UINT32 guiVSurfaceIndex = 0;
|
|
UINT32 guiVSurfaceSize = 0;
|
|
UINT32 guiVSurfaceTotalAdded = 0;
|
|
|
|
#ifdef _DEBUG
|
|
enum
|
|
{
|
|
DEBUGSTR_NONE,
|
|
DEBUGSTR_SETVIDEOSURFACETRANSPARENCY,
|
|
DEBUGSTR_ADDVIDEOSURFACEREGION,
|
|
DEBUGSTR_GETVIDEOSURFACEDESCRIPTION,
|
|
DEBUGSTR_BLTVIDEOSURFACE_DST,
|
|
DEBUGSTR_BLTVIDEOSURFACE_SRC,
|
|
DEBUGSTR_COLORFILLVIDEOSURFACEAREA,
|
|
DEBUGSTR_SHADOWVIDEOSURFACERECT,
|
|
DEBUGSTR_BLTSTRETCHVIDEOSURFACE_DST,
|
|
DEBUGSTR_BLTSTRETCHVIDEOSURFACE_SRC,
|
|
DEBUGSTR_DELETEVIDEOSURFACEFROMINDEX
|
|
};
|
|
|
|
UINT8 gubVSDebugCode = 0;
|
|
|
|
void CheckValidVSurfaceIndex( UINT32 uiIndex );
|
|
#endif
|
|
|
|
INT32 giMemUsedInSurfaces;
|
|
|
|
|
|
//OBSOLETE!!!!!!!!!
|
|
HLIST ghVideoSurfaces = NULL;
|
|
//OBSOLETE!!!!!!!!!
|
|
|
|
|
|
HVSURFACE ghPrimary = NULL;
|
|
HVSURFACE ghBackBuffer = NULL;
|
|
HVSURFACE ghFrameBuffer = NULL;
|
|
HVSURFACE ghMouseBuffer = NULL;
|
|
|
|
#include <map>
|
|
|
|
extern std::map<UINT32,ClipRectangle> g_SurfaceRectangle;
|
|
|
|
namespace SurfaceData
|
|
{
|
|
typedef void* tSurface;
|
|
std::map<tID,tSurface> _surfaceID;
|
|
std::map<tSurface,BYTE*> _surfaceData;
|
|
std::map<BYTE*,tID> _surfaceOfData;
|
|
|
|
void RegisterSurface(tID surfaceID, HVSURFACE surface)
|
|
{
|
|
SurfaceData::_surfaceID[surfaceID] = surface;
|
|
g_SurfaceRectangle[surfaceID].SetRect(surface->usWidth, surface->usHeight);
|
|
}
|
|
void UnRegisterSurface(tID surfaceID)
|
|
{
|
|
std::map<tID,tSurface>::iterator it = SurfaceData::_surfaceID.find(surfaceID);
|
|
if(it != SurfaceData::_surfaceID.end())
|
|
{
|
|
g_SurfaceRectangle.erase(it->first);
|
|
SurfaceData::_surfaceID.erase(it);
|
|
}
|
|
}
|
|
void UnRegisterSurface(HVSURFACE surface)
|
|
{
|
|
std::map<tID,tSurface>::iterator it = SurfaceData::_surfaceID.begin();
|
|
for(;it != SurfaceData::_surfaceID.end(); it++)
|
|
{
|
|
if(it->second == surface)
|
|
{
|
|
SurfaceData::_surfaceID.erase(it);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
BYTE* SetSurfaceData(tID surfaceID, BYTE* data)
|
|
{
|
|
std::map<tID,tSurface>::iterator sit = SurfaceData::_surfaceID.find(surfaceID);
|
|
if(sit != SurfaceData::_surfaceID.end())
|
|
{
|
|
SurfaceData::_surfaceData[sit->second] = data;
|
|
SurfaceData::_surfaceOfData[data] = surfaceID;
|
|
return data;
|
|
}
|
|
SGP_THROW(L"Unregistered surface ID");
|
|
}
|
|
BYTE* SetSurfaceData(HVSURFACE surface, BYTE* data)
|
|
{
|
|
std::map<tID,tSurface>::iterator sit = SurfaceData::_surfaceID.begin();
|
|
for(;sit != SurfaceData::_surfaceID.end(); ++sit)
|
|
{
|
|
if(sit->second = surface)
|
|
{
|
|
SurfaceData::_surfaceData[sit->second] = data;
|
|
SurfaceData::_surfaceOfData[data] = sit->first;
|
|
return data;
|
|
}
|
|
}
|
|
SGP_THROW(L"Unregistered surface");
|
|
}
|
|
void ReleaseSurfaceData(tID surfaceID)
|
|
{
|
|
// does a surface with this ID exist
|
|
std::map<tID,tSurface>::iterator sit = SurfaceData::_surfaceID.find(surfaceID);
|
|
if(sit != SurfaceData::_surfaceID.end())
|
|
{
|
|
// get saved data of this surface
|
|
std::map<tSurface,BYTE*>::iterator dit = SurfaceData::_surfaceData.find(sit->second);
|
|
if(dit != SurfaceData::_surfaceData.end())
|
|
{
|
|
// as data pointer is going to be removed, release its connection to a surface ID
|
|
std::map<BYTE*,tID>::iterator it = SurfaceData::_surfaceOfData.find(dit->second);
|
|
if(it != SurfaceData::_surfaceOfData.end())
|
|
{
|
|
SurfaceData::_surfaceOfData.erase(it);
|
|
}
|
|
// finally remove data pointer
|
|
SurfaceData::_surfaceData.erase(dit);
|
|
}
|
|
}
|
|
}
|
|
void ReleaseSurfaceData(HVSURFACE surface)
|
|
{
|
|
// get saved data of this surface
|
|
std::map<tSurface,BYTE*>::iterator dit = SurfaceData::_surfaceData.find(surface);
|
|
if(dit != SurfaceData::_surfaceData.end())
|
|
{
|
|
// as data pointer is going to be removed, release its connection to a surface ID
|
|
std::map<BYTE*,tID>::iterator it = SurfaceData::_surfaceOfData.find(dit->second);
|
|
if(it != SurfaceData::_surfaceOfData.end())
|
|
{
|
|
_surfaceOfData.erase(it);
|
|
}
|
|
// finally remove data pointer
|
|
SurfaceData::_surfaceData.erase(dit);
|
|
}
|
|
}
|
|
|
|
BYTE* SetApplicationData(BYTE* data)
|
|
{
|
|
tID id = (tID)(data);
|
|
SurfaceData::_surfaceOfData[data] = id;
|
|
return data;
|
|
}
|
|
void ReleaseApplicationData(BYTE* data)
|
|
{
|
|
tID id = (tID)(data);
|
|
std::map<BYTE*,tID>::iterator it = SurfaceData::_surfaceOfData.find(data);
|
|
if(it != SurfaceData::_surfaceOfData.end())
|
|
{
|
|
g_SurfaceRectangle.erase(it->second);
|
|
SurfaceData::_surfaceOfData.erase(it);
|
|
}
|
|
return ReleaseSurfaceData(id);
|
|
}
|
|
|
|
tID GetSurfaceID(BYTE* data)
|
|
{
|
|
std::map<BYTE*,tID>::iterator it = SurfaceData::_surfaceOfData.find(data);
|
|
if(it != SurfaceData::_surfaceOfData.end())
|
|
{
|
|
return it->second;
|
|
}
|
|
//SGP_THROW(L"Pointer to surface invalid");
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
ClipRectangle::ClipRectangle()
|
|
{
|
|
cr.iLeft = 0;
|
|
cr.iTop = 0;
|
|
cr.iRight = 0;
|
|
cr.iBottom = 0;
|
|
};
|
|
|
|
void ClipRectangle::SetRect(SGPRect const& rect)
|
|
{
|
|
Set(rect.iLeft, rect.iTop, rect.iRight, rect.iBottom);
|
|
}
|
|
void ClipRectangle::SetRect(unsigned int w, unsigned int h, int x, int y)
|
|
{
|
|
Set(x,y,x+w,y+h);
|
|
}
|
|
void ClipRectangle::Set(int x1, int y1, int x2, int y2)
|
|
{
|
|
cr.iLeft = x1;
|
|
cr.iRight = x2;
|
|
cr.iTop = y1;
|
|
cr.iBottom = y2;
|
|
}
|
|
|
|
/**
|
|
* @returns:
|
|
* NoClip : value references are not modified
|
|
* FullClip : value references are not modified, as the values lie completely outside. Why bother doing the extra work.
|
|
* PartialClip : value references are modified
|
|
*/
|
|
ClipRectangle::ClipType ClipRectangle::Clip(int& x, int& y, unsigned int& w, unsigned int& h)
|
|
{
|
|
int right = x + w - 1;
|
|
int bottom = y + h - 1;
|
|
ClipType ct;
|
|
if( (ct = Clip(x,y,right,bottom)) == PartialClip)
|
|
{
|
|
w = right - x + 1;
|
|
h = bottom - y + 1;
|
|
}
|
|
return ct;
|
|
}
|
|
ClipRectangle::ClipType ClipRectangle::Clip(int& x1, int& y1, int& x2, int& y2)
|
|
{
|
|
if( (x1 >= cr.iLeft) &&
|
|
(x2 <= cr.iRight) &&
|
|
(y1 >= cr.iTop) &&
|
|
(y2 <= cr.iBottom) )
|
|
{
|
|
return NoClip;
|
|
}
|
|
if( (x1 > cr.iRight) || // right of rectangle
|
|
(x2 < cr.iLeft) || // left of rectangle
|
|
(y1 > cr.iBottom) || // below rectangle
|
|
(y2 < cr.iTop) ) // above rectangle
|
|
{
|
|
return FullClip;
|
|
}
|
|
if( x1 < cr.iLeft) x1 = cr.iLeft;
|
|
if( x2 > cr.iRight) x2 = cr.iRight;
|
|
if( y1 < cr.iTop) y1 = cr.iTop;
|
|
if( y2 > cr.iBottom) y2 = cr.iBottom;
|
|
return PartialClip;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Video Surface Manager functions
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOLEAN InitializeVideoSurfaceManager( )
|
|
{
|
|
//Shouldn't be calling this if the video surface manager already exists.
|
|
//Call shutdown first...
|
|
Assert( !gpVSurfaceHead );
|
|
Assert( !gpVSurfaceTail );
|
|
RegisterDebugTopic(TOPIC_VIDEOSURFACE, "Video Surface Manager");
|
|
gpVSurfaceHead = gpVSurfaceTail = NULL;
|
|
|
|
giMemUsedInSurfaces = 0;
|
|
|
|
// Create primary and backbuffer from globals
|
|
if ( !SetPrimaryVideoSurfaces( ) )
|
|
{
|
|
DbgMessage(TOPIC_VIDEOSURFACE, DBG_LEVEL_1, String( "Could not create primary surfaces" ) );
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
BOOLEAN ShutdownVideoSurfaceManager( )
|
|
{
|
|
VSURFACE_NODE *curr;
|
|
|
|
DbgMessage(TOPIC_VIDEOSURFACE, DBG_LEVEL_0, "Shutting down the Video Surface manager");
|
|
|
|
// Delete primary viedeo surfaces
|
|
DeletePrimaryVideoSurfaces( );
|
|
|
|
while( gpVSurfaceHead )
|
|
{
|
|
curr = gpVSurfaceHead;
|
|
gpVSurfaceHead = gpVSurfaceHead->next;
|
|
DeleteVideoSurface( curr->hVSurface );
|
|
#ifdef SGP_VIDEO_DEBUGGING
|
|
if( curr->pName )
|
|
MemFree( curr->pName );
|
|
if( curr->pCode )
|
|
MemFree( curr->pCode );
|
|
#endif
|
|
MemFree( curr );
|
|
}
|
|
gpVSurfaceHead = NULL;
|
|
gpVSurfaceTail = NULL;
|
|
guiVSurfaceIndex = 0;
|
|
guiVSurfaceSize = 0;
|
|
guiVSurfaceTotalAdded = 0;
|
|
UnRegisterDebugTopic(TOPIC_VIDEOSURFACE, "Video Objects");
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN RestoreVideoSurfaces( )
|
|
{
|
|
VSURFACE_NODE *curr;
|
|
|
|
//
|
|
// Loop through Video Surfaces and Restore
|
|
//
|
|
curr = gpVSurfaceTail;
|
|
while( curr )
|
|
{
|
|
if( !RestoreVideoSurface( curr->hVSurface ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
curr = curr->prev;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN AddStandardVideoSurface( VSURFACE_DESC *pVSurfaceDesc, UINT32 *puiIndex )
|
|
{
|
|
|
|
HVSURFACE hVSurface;
|
|
|
|
// Assertions
|
|
Assert( puiIndex );
|
|
Assert( pVSurfaceDesc );
|
|
|
|
// Create video object
|
|
hVSurface = CreateVideoSurface( pVSurfaceDesc );
|
|
|
|
if( !hVSurface )
|
|
{
|
|
// Video Object will set error condition.
|
|
return FALSE ;
|
|
}
|
|
|
|
// Set transparency to default
|
|
SetVideoSurfaceTransparencyColor( hVSurface, FROMRGB( 0, 0, 0 ) );
|
|
|
|
// Set into video object list
|
|
if( gpVSurfaceHead )
|
|
{ //Add node after tail
|
|
gpVSurfaceTail->next = (VSURFACE_NODE*)MemAlloc( sizeof( VSURFACE_NODE ) );
|
|
Assert( gpVSurfaceTail->next ); //out of memory?
|
|
gpVSurfaceTail->next->prev = gpVSurfaceTail;
|
|
gpVSurfaceTail->next->next = NULL;
|
|
gpVSurfaceTail = gpVSurfaceTail->next;
|
|
}
|
|
else
|
|
{ //new list
|
|
gpVSurfaceHead = (VSURFACE_NODE*)MemAlloc( sizeof( VSURFACE_NODE ) );
|
|
Assert( gpVSurfaceHead ); //out of memory?
|
|
gpVSurfaceHead->prev = gpVSurfaceHead->next = NULL;
|
|
gpVSurfaceTail = gpVSurfaceHead;
|
|
}
|
|
#ifdef SGP_VIDEO_DEBUGGING
|
|
gpVSurfaceTail->pName = NULL;
|
|
gpVSurfaceTail->pCode = NULL;
|
|
#endif
|
|
//Set the hVSurface into the node.
|
|
gpVSurfaceTail->hVSurface = hVSurface;
|
|
gpVSurfaceTail->uiIndex = guiVSurfaceIndex+=2;
|
|
*puiIndex = gpVSurfaceTail->uiIndex;
|
|
SurfaceData::RegisterSurface(*puiIndex, hVSurface);
|
|
Assert( guiVSurfaceIndex < 0xfffffff0 ); //unlikely that we will ever use 2 billion VSurfaces!
|
|
//We would have to create about 70 VSurfaces per second for 1 year straight to achieve this...
|
|
guiVSurfaceSize++;
|
|
guiVSurfaceTotalAdded++;
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
|
|
BYTE *LockVideoSurface( UINT32 uiVSurface, UINT32 *puiPitch )
|
|
{
|
|
VSURFACE_NODE *curr;
|
|
|
|
if ( iUseWinFonts ) {
|
|
CurrentSurface = uiVSurface;
|
|
}
|
|
//
|
|
// Check if given backbuffer or primary buffer
|
|
//
|
|
if ( uiVSurface == PRIMARY_SURFACE )
|
|
{
|
|
return SurfaceData::SetSurfaceData(uiVSurface, (BYTE *)LockPrimarySurface( puiPitch ));
|
|
}
|
|
|
|
if ( uiVSurface == BACKBUFFER )
|
|
{
|
|
return SurfaceData::SetSurfaceData(uiVSurface, (BYTE *)LockBackBuffer( puiPitch ));
|
|
}
|
|
|
|
if ( uiVSurface == FRAME_BUFFER )
|
|
{
|
|
return SurfaceData::SetSurfaceData(uiVSurface, (BYTE *)LockFrameBuffer( puiPitch ));
|
|
}
|
|
|
|
if ( uiVSurface == MOUSE_BUFFER )
|
|
{
|
|
return SurfaceData::SetSurfaceData(uiVSurface, (BYTE *)LockMouseBuffer( puiPitch ));
|
|
}
|
|
|
|
//
|
|
// Otherwise, use list
|
|
//
|
|
|
|
curr = gpVSurfaceHead;
|
|
while( curr )
|
|
{
|
|
if( curr->uiIndex == uiVSurface )
|
|
{
|
|
break;
|
|
}
|
|
curr = curr->next;
|
|
}
|
|
if( !curr )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Lock buffer
|
|
//
|
|
|
|
return SurfaceData::SetSurfaceData(uiVSurface, LockVideoSurfaceBuffer( curr->hVSurface, puiPitch ));
|
|
|
|
}
|
|
|
|
void UnLockVideoSurface( UINT32 uiVSurface )
|
|
{
|
|
VSURFACE_NODE *curr;
|
|
|
|
SurfaceData::ReleaseSurfaceData(uiVSurface);
|
|
//
|
|
// Check if given backbuffer or primary buffer
|
|
//
|
|
if ( uiVSurface == PRIMARY_SURFACE )
|
|
{
|
|
UnlockPrimarySurface();
|
|
return;
|
|
}
|
|
|
|
if ( uiVSurface == BACKBUFFER )
|
|
{
|
|
UnlockBackBuffer();
|
|
return;
|
|
}
|
|
|
|
if ( uiVSurface == FRAME_BUFFER )
|
|
{
|
|
UnlockFrameBuffer();
|
|
return;
|
|
}
|
|
|
|
if ( uiVSurface == MOUSE_BUFFER )
|
|
{
|
|
UnlockMouseBuffer();
|
|
return;
|
|
}
|
|
|
|
curr = gpVSurfaceHead;
|
|
while( curr )
|
|
{
|
|
if( curr->uiIndex == uiVSurface )
|
|
{
|
|
break;
|
|
}
|
|
curr = curr->next;
|
|
}
|
|
if( !curr )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// unlock buffer
|
|
//
|
|
|
|
UnLockVideoSurfaceBuffer( curr->hVSurface );
|
|
}
|
|
|
|
BOOLEAN SetVideoSurfaceTransparency( UINT32 uiIndex, COLORVAL TransColor )
|
|
{
|
|
HVSURFACE hVSurface;
|
|
|
|
//
|
|
// Get Video Surface
|
|
//
|
|
|
|
#ifdef _DEBUG
|
|
gubVSDebugCode = DEBUGSTR_SETVIDEOSURFACETRANSPARENCY;
|
|
#endif
|
|
CHECKF( GetVideoSurface( &hVSurface, uiIndex ) );
|
|
|
|
//
|
|
// Set transparency
|
|
//
|
|
|
|
SetVideoSurfaceTransparencyColor( hVSurface, TransColor );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN AddVideoSurfaceRegion( UINT32 uiIndex, VSURFACE_REGION *pNewRegion )
|
|
{
|
|
HVSURFACE hVSurface;
|
|
|
|
//
|
|
// Get Video Surface
|
|
//
|
|
|
|
#ifdef _DEBUG
|
|
gubVSDebugCode = DEBUGSTR_ADDVIDEOSURFACEREGION;
|
|
#endif
|
|
CHECKF( GetVideoSurface( &hVSurface, uiIndex ) );
|
|
|
|
//
|
|
// Add Region
|
|
//
|
|
|
|
CHECKF( AddVSurfaceRegion( hVSurface, pNewRegion ) );
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
BOOLEAN GetVideoSurfaceDescription( UINT32 uiIndex, UINT16 *usWidth, UINT16 *usHeight, UINT8 *ubBitDepth )
|
|
{
|
|
HVSURFACE hVSurface;
|
|
|
|
Assert( usWidth != NULL );
|
|
Assert( usHeight != NULL );
|
|
Assert( ubBitDepth != NULL );
|
|
|
|
//
|
|
// Get Video Surface
|
|
//
|
|
|
|
#ifdef _DEBUG
|
|
gubVSDebugCode = DEBUGSTR_GETVIDEOSURFACEDESCRIPTION;
|
|
#endif
|
|
CHECKF( GetVideoSurface( &hVSurface, uiIndex ) );
|
|
|
|
*usWidth = hVSurface->usWidth;
|
|
*usHeight = hVSurface->usHeight;
|
|
*ubBitDepth = hVSurface->ubBitDepth;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN GetVideoSurface( HVSURFACE *hVSurface, UINT32 uiIndex )
|
|
{
|
|
VSURFACE_NODE *curr;
|
|
|
|
#ifdef _DEBUG
|
|
CheckValidVSurfaceIndex( uiIndex );
|
|
#endif
|
|
|
|
if ( uiIndex == PRIMARY_SURFACE )
|
|
{
|
|
*hVSurface = ghPrimary;
|
|
return TRUE;
|
|
}
|
|
|
|
if ( uiIndex == BACKBUFFER )
|
|
{
|
|
*hVSurface = ghBackBuffer;
|
|
return TRUE;
|
|
}
|
|
|
|
if ( uiIndex == FRAME_BUFFER )
|
|
{
|
|
*hVSurface = ghFrameBuffer;
|
|
return TRUE;
|
|
}
|
|
|
|
if ( uiIndex == MOUSE_BUFFER )
|
|
{
|
|
*hVSurface = ghMouseBuffer;
|
|
return TRUE;
|
|
}
|
|
|
|
curr = gpVSurfaceHead;
|
|
while( curr )
|
|
{
|
|
if( curr->uiIndex == uiIndex )
|
|
{
|
|
*hVSurface = curr->hVSurface;
|
|
return TRUE;
|
|
}
|
|
curr = curr->next;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN SetPrimaryVideoSurfaces( )
|
|
{
|
|
LPDIRECTDRAWSURFACE2 pSurface;
|
|
|
|
// Delete surfaces if they exist
|
|
DeletePrimaryVideoSurfaces( );
|
|
|
|
//
|
|
// Get Primary surface
|
|
//
|
|
pSurface = GetPrimarySurfaceObject();
|
|
CHECKF( pSurface != NULL );
|
|
|
|
ghPrimary = CreateVideoSurfaceFromDDSurface( pSurface );
|
|
CHECKF( ghPrimary != NULL );
|
|
SurfaceData::RegisterSurface(PRIMARY_SURFACE,ghPrimary);
|
|
|
|
//
|
|
// Get Backbuffer surface
|
|
//
|
|
|
|
pSurface = GetBackBufferObject( );
|
|
CHECKF( pSurface != NULL );
|
|
|
|
ghBackBuffer = CreateVideoSurfaceFromDDSurface( pSurface );
|
|
CHECKF( ghBackBuffer != NULL );
|
|
SurfaceData::RegisterSurface(BACKBUFFER,ghBackBuffer);
|
|
|
|
//
|
|
// Get mouse buffer surface
|
|
//
|
|
pSurface = GetMouseBufferObject( );
|
|
CHECKF( pSurface != NULL );
|
|
|
|
ghMouseBuffer = CreateVideoSurfaceFromDDSurface( pSurface );
|
|
CHECKF( ghMouseBuffer != NULL );
|
|
SurfaceData::RegisterSurface(MOUSE_BUFFER,ghMouseBuffer);
|
|
|
|
|
|
//
|
|
// Get frame buffer surface
|
|
//
|
|
|
|
pSurface = GetFrameBufferObject( );
|
|
CHECKF( pSurface != NULL );
|
|
|
|
ghFrameBuffer = CreateVideoSurfaceFromDDSurface( pSurface );
|
|
CHECKF( ghFrameBuffer != NULL );
|
|
SurfaceData::RegisterSurface(FRAME_BUFFER,ghFrameBuffer);
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
void DeletePrimaryVideoSurfaces( )
|
|
{
|
|
//
|
|
// If globals are not null, delete them
|
|
//
|
|
|
|
if ( ghPrimary != NULL )
|
|
{
|
|
SurfaceData::UnRegisterSurface(ghPrimary);
|
|
DeleteVideoSurface( ghPrimary );
|
|
ghPrimary = NULL;
|
|
}
|
|
|
|
if ( ghBackBuffer != NULL )
|
|
{
|
|
SurfaceData::UnRegisterSurface(ghBackBuffer);
|
|
DeleteVideoSurface( ghBackBuffer );
|
|
ghBackBuffer = NULL;
|
|
}
|
|
|
|
if ( ghFrameBuffer != NULL )
|
|
{
|
|
SurfaceData::UnRegisterSurface(ghFrameBuffer);
|
|
DeleteVideoSurface( ghFrameBuffer );
|
|
ghFrameBuffer = NULL;
|
|
}
|
|
|
|
if ( ghMouseBuffer != NULL )
|
|
{
|
|
SurfaceData::UnRegisterSurface(ghMouseBuffer);
|
|
DeleteVideoSurface( ghMouseBuffer );
|
|
ghMouseBuffer = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Given an index to the dest and src vobject contained in our private VSurface list
|
|
// Based on flags, blit accordingly
|
|
// There are two types, a BltFast and a Blt. BltFast is 10% faster, uses no
|
|
// clipping lists
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOLEAN BltVideoSurface(UINT32 uiDestVSurface, UINT32 uiSrcVSurface, UINT16 usRegionIndex, INT32 iDestX, INT32 iDestY, UINT32 fBltFlags, blt_vs_fx *pBltFx )
|
|
{
|
|
|
|
HVSURFACE hDestVSurface;
|
|
HVSURFACE hSrcVSurface;
|
|
|
|
#ifdef _DEBUG
|
|
gubVSDebugCode = DEBUGSTR_BLTVIDEOSURFACE_DST;
|
|
#endif
|
|
if( !GetVideoSurface( &hDestVSurface, uiDestVSurface ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
#ifdef _DEBUG
|
|
gubVSDebugCode = DEBUGSTR_BLTVIDEOSURFACE_SRC;
|
|
#endif
|
|
if( !GetVideoSurface( &hSrcVSurface, uiSrcVSurface ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
if ( !BltVideoSurfaceToVideoSurface( hDestVSurface, hSrcVSurface, usRegionIndex, iDestX, iDestY, fBltFlags, pBltFx ) )
|
|
{ // VO Blitter will set debug messages for error conditions
|
|
return FALSE ;
|
|
}
|
|
return TRUE ;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Fills an rectangular area with a specified color value.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOLEAN ColorFillVideoSurfaceArea(UINT32 uiDestVSurface, INT32 iDestX1, INT32 iDestY1, INT32 iDestX2, INT32 iDestY2, UINT16 Color16BPP)
|
|
{
|
|
blt_vs_fx BltFx;
|
|
HVSURFACE hDestVSurface;
|
|
SGPRect Clip;
|
|
|
|
#ifdef _DEBUG
|
|
gubVSDebugCode = DEBUGSTR_COLORFILLVIDEOSURFACEAREA;
|
|
#endif
|
|
if( !GetVideoSurface( &hDestVSurface, uiDestVSurface ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BltFx.ColorFill = Color16BPP;
|
|
BltFx.DestRegion = 0;
|
|
|
|
//
|
|
// Clip fill region coords
|
|
//
|
|
|
|
GetClippingRect(&Clip);
|
|
|
|
if(iDestX1 < Clip.iLeft)
|
|
iDestX1 = Clip.iLeft;
|
|
|
|
if(iDestX1 > Clip.iRight)
|
|
return(FALSE);
|
|
|
|
if(iDestX2 > Clip.iRight)
|
|
iDestX2 = Clip.iRight;
|
|
|
|
if(iDestX2 < Clip.iLeft)
|
|
return(FALSE);
|
|
|
|
if(iDestY1 < Clip.iTop)
|
|
iDestY1 = Clip.iTop;
|
|
|
|
if(iDestY1 > Clip.iBottom)
|
|
return(FALSE);
|
|
|
|
if(iDestY2 > Clip.iBottom)
|
|
iDestY2 = Clip.iBottom;
|
|
|
|
if(iDestY2 < Clip.iTop)
|
|
return(FALSE);
|
|
|
|
if((iDestX2 <= iDestX1) || (iDestY2 <= iDestY1))
|
|
return(FALSE);
|
|
|
|
BltFx.SrcRect.iLeft = BltFx.FillRect.iLeft = iDestX1;
|
|
BltFx.SrcRect.iTop = BltFx.FillRect.iTop = iDestY1;
|
|
BltFx.SrcRect.iRight = BltFx.FillRect.iRight = iDestX2;
|
|
BltFx.SrcRect.iBottom = BltFx.FillRect.iBottom = iDestY2;
|
|
|
|
return( FillSurfaceRect( hDestVSurface, &BltFx ) );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Fills an rectangular area with a specified image value.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOLEAN ImageFillVideoSurfaceArea(UINT32 uiDestVSurface, INT32 iDestX1, INT32 iDestY1, INT32 iDestX2, INT32 iDestY2, HVOBJECT BkgrndImg, UINT16 Index, INT16 Ox, INT16 Oy)
|
|
{
|
|
INT16 xc,yc,hblits,wblits,aw,pw,ah,ph,w,h,xo,yo;
|
|
ETRLEObject *pTrav;
|
|
SGPRect NewClip,OldClip;
|
|
|
|
pTrav = &(BkgrndImg->pETRLEObject[Index]);
|
|
ph = (INT16)(pTrav->usHeight+pTrav->sOffsetY);
|
|
pw = (INT16)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
ah = (INT16)(iDestY2-iDestY1);
|
|
aw = (INT16)(iDestX2-iDestX1);
|
|
|
|
Ox %= pw;
|
|
Oy %= ph;
|
|
|
|
if(Ox>0)
|
|
Ox -= pw;
|
|
xo = (-Ox)%pw;
|
|
|
|
if(Oy>0)
|
|
Oy -= ph;
|
|
yo = (-Oy)%ph;
|
|
|
|
if(Ox<0)
|
|
xo = (-Ox)%pw;
|
|
else
|
|
{
|
|
xo = pw-(Ox%pw);
|
|
Ox -= pw;
|
|
}
|
|
|
|
if(Oy<0)
|
|
yo = (-Oy)%ph;
|
|
else
|
|
{
|
|
yo = ph-(Oy%pw);
|
|
Oy -= ph;
|
|
}
|
|
|
|
hblits = ((ah+yo)/ph) + (((ah+yo)%ph)?1:0);
|
|
wblits = ((aw+xo)/pw) + (((aw+xo)%pw)?1:0);
|
|
|
|
if((hblits==0) || (wblits==0))
|
|
return(FALSE);
|
|
|
|
//
|
|
// Clip fill region coords
|
|
//
|
|
|
|
GetClippingRect(&OldClip);
|
|
|
|
NewClip.iLeft=iDestX1;
|
|
NewClip.iTop=iDestY1;
|
|
NewClip.iRight=iDestX2;
|
|
NewClip.iBottom=iDestY2;
|
|
|
|
if(NewClip.iLeft < OldClip.iLeft)
|
|
NewClip.iLeft = OldClip.iLeft;
|
|
|
|
if(NewClip.iLeft > OldClip.iRight)
|
|
return(FALSE);
|
|
|
|
if(NewClip.iRight > OldClip.iRight)
|
|
NewClip.iRight = OldClip.iRight;
|
|
|
|
if(NewClip.iRight < OldClip.iLeft)
|
|
return(FALSE);
|
|
|
|
if(NewClip.iTop < OldClip.iTop)
|
|
NewClip.iTop = OldClip.iTop;
|
|
|
|
if(NewClip.iTop > OldClip.iBottom)
|
|
return(FALSE);
|
|
|
|
if(NewClip.iBottom > OldClip.iBottom)
|
|
NewClip.iBottom = OldClip.iBottom;
|
|
|
|
if(NewClip.iBottom < OldClip.iTop)
|
|
return(FALSE);
|
|
|
|
if((NewClip.iRight <= NewClip.iLeft) || (NewClip.iBottom <= NewClip.iTop))
|
|
return(FALSE);
|
|
|
|
SetClippingRect(&NewClip);
|
|
|
|
yc = (INT16)iDestY1;
|
|
for(h=0;h<hblits;h++)
|
|
{
|
|
xc = (INT16)iDestX1;
|
|
for(w=0;w<wblits;w++)
|
|
{
|
|
BltVideoObject(uiDestVSurface, BkgrndImg, Index, xc+Ox, yc+Oy, VO_BLT_SRCTRANSPARENCY, NULL);
|
|
xc += pw;
|
|
}
|
|
yc += ph;
|
|
}
|
|
|
|
SetClippingRect(&OldClip);
|
|
return(TRUE);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Video Surface Manipulation Functions
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HVSURFACE CreateVideoSurface( VSURFACE_DESC *VSurfaceDesc )
|
|
{
|
|
LPDIRECTDRAW2 lpDD2Object;
|
|
DDSURFACEDESC SurfaceDescription;
|
|
DDPIXELFORMAT PixelFormat;
|
|
LPDIRECTDRAWSURFACE lpDDS;
|
|
LPDIRECTDRAWSURFACE2 lpDDS2;
|
|
HVSURFACE hVSurface;
|
|
HIMAGE hImage = NULL;
|
|
SGPRect tempRect;
|
|
UINT16 usHeight;
|
|
UINT16 usWidth;
|
|
UINT8 ubBitDepth;
|
|
UINT32 fMemUsage;
|
|
|
|
UINT32 uiRBitMask;
|
|
UINT32 uiGBitMask;
|
|
UINT32 uiBBitMask;
|
|
|
|
//Clear the memory
|
|
memset( &SurfaceDescription, 0, sizeof( DDSURFACEDESC ) );
|
|
|
|
//
|
|
// Get Direct Draw Object
|
|
//
|
|
|
|
lpDD2Object = GetDirectDraw2Object( );
|
|
|
|
//
|
|
// The description structure contains memory usage flag
|
|
//
|
|
fMemUsage = VSurfaceDesc->fCreateFlags;
|
|
|
|
//
|
|
// Check creation options
|
|
//
|
|
|
|
//do
|
|
//{
|
|
//
|
|
// Check if creating from file
|
|
//
|
|
|
|
if ( VSurfaceDesc->fCreateFlags & VSURFACE_CREATE_FROMFILE )
|
|
{
|
|
//
|
|
// Create himage object from file
|
|
//
|
|
ImageFileType::TestOrder order = ImageFileType::JPC_FALLBACK;
|
|
if(VSurfaceDesc->fCreateFlags & VSURFACE_CREATE_FROMJPC) {
|
|
order = ImageFileType::JPC;
|
|
} if(VSurfaceDesc->fCreateFlags & VSURFACE_CREATE_FROMJPC_FALLBACK) {
|
|
order = ImageFileType::JPC_FALLBACK;
|
|
} if(VSurfaceDesc->fCreateFlags & VSURFACE_CREATE_FROMPNG) {
|
|
order = ImageFileType::PNG;
|
|
} if(VSurfaceDesc->fCreateFlags & VSURFACE_CREATE_FROMPNG_FALLBACK) {
|
|
order = ImageFileType::PNG_FALLBACK;
|
|
}
|
|
|
|
SGP_THROW_IFFALSE(hImage = CreateImage( VSurfaceDesc->ImageFile, IMAGE_ALLIMAGEDATA, order ),
|
|
_BS(L"Could not create video surface from file : ") << vfs::String(VSurfaceDesc->ImageFile) << _BS::wget);
|
|
|
|
if ( hImage == NULL )
|
|
{
|
|
DbgMessage( TOPIC_VIDEOSURFACE, DBG_LEVEL_2, "Invalid Image Filename given" );
|
|
return( NULL );
|
|
}
|
|
|
|
//
|
|
// Set values from himage
|
|
//
|
|
usHeight = hImage->usHeight;
|
|
usWidth = hImage->usWidth;
|
|
ubBitDepth = hImage->ubBitDepth;
|
|
// break;
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// If here, no special options given,
|
|
// Set values from given description structure
|
|
//
|
|
|
|
usHeight = VSurfaceDesc->usHeight;
|
|
usWidth = VSurfaceDesc->usWidth;
|
|
ubBitDepth = VSurfaceDesc->ubBitDepth;
|
|
|
|
}
|
|
//while( FALSE );
|
|
|
|
//
|
|
// Assertions
|
|
//
|
|
|
|
Assert ( usHeight > 0 );
|
|
Assert ( usWidth > 0 );
|
|
|
|
//
|
|
// Setup Direct Draw Description
|
|
// First do Pixel Format
|
|
//
|
|
|
|
memset( &PixelFormat, 0, sizeof( PixelFormat ) );
|
|
PixelFormat.dwSize = sizeof( DDPIXELFORMAT );
|
|
|
|
switch( ubBitDepth )
|
|
{
|
|
|
|
case 8:
|
|
|
|
PixelFormat.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8;
|
|
PixelFormat.dwRGBBitCount = 8;
|
|
break;
|
|
|
|
case 16:
|
|
// BF: handle 24 bpp and 32 bpp images as 16 bpp ones = convert larger color space to the smaller one
|
|
case 24:
|
|
case 32:
|
|
|
|
PixelFormat.dwFlags = DDPF_RGB;
|
|
PixelFormat.dwRGBBitCount = 16;
|
|
|
|
//
|
|
// Get current Pixel Format from DirectDraw
|
|
//
|
|
|
|
// We're using pixel formats too -- DB/Wiz
|
|
|
|
CHECKF( GetPrimaryRGBDistributionMasks( &uiRBitMask, &uiGBitMask, &uiBBitMask ) );
|
|
PixelFormat.dwRBitMask = uiRBitMask;
|
|
PixelFormat.dwGBitMask = uiGBitMask;
|
|
PixelFormat.dwBBitMask = uiBBitMask;
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// If Here, an invalid format was given
|
|
//
|
|
|
|
DbgMessage( TOPIC_VIDEOSURFACE, DBG_LEVEL_2, "Invalid BPP value, can only be 8 or 16." );
|
|
return( FALSE );
|
|
}
|
|
|
|
SurfaceDescription.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
|
|
|
|
//
|
|
// Do memory description, based on specified flags
|
|
//
|
|
|
|
do
|
|
{
|
|
if ( fMemUsage & VSURFACE_DEFAULT_MEM_USAGE )
|
|
{
|
|
SurfaceDescription.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
|
break;
|
|
}
|
|
if ( fMemUsage & VSURFACE_VIDEO_MEM_USAGE )
|
|
{
|
|
SurfaceDescription.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
|
break;
|
|
}
|
|
|
|
if ( fMemUsage & VSURFACE_SYSTEM_MEM_USAGE )
|
|
{
|
|
SurfaceDescription.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Once here, no mem flags were given, use default
|
|
//
|
|
|
|
SurfaceDescription.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
|
|
|
} while( FALSE );
|
|
|
|
//
|
|
// Set other, common structure elements
|
|
//
|
|
|
|
SurfaceDescription.dwSize = sizeof(DDSURFACEDESC);
|
|
SurfaceDescription.dwWidth = usWidth;
|
|
SurfaceDescription.dwHeight = usHeight;
|
|
SurfaceDescription.ddpfPixelFormat = PixelFormat;
|
|
|
|
//
|
|
// Create Surface
|
|
//
|
|
|
|
DDCreateSurface ( lpDD2Object, &SurfaceDescription, &lpDDS, &lpDDS2 );
|
|
|
|
//
|
|
// Allocate memory for Video Surface data and initialize
|
|
//
|
|
|
|
hVSurface = (HVSURFACE) MemAlloc( sizeof( SGPVSurface ) );
|
|
memset( hVSurface, 0, sizeof( SGPVSurface ) );
|
|
CHECKF( hVSurface != NULL );
|
|
|
|
hVSurface->usHeight = usHeight;
|
|
hVSurface->usWidth = usWidth;
|
|
// BF : since we use a 16bpp framebuffer and images are converted to that format,
|
|
// there is no need to set the surface bit depth to a higher value than 16
|
|
hVSurface->ubBitDepth = ubBitDepth > 16 ? 16 : ubBitDepth;
|
|
hVSurface->pSurfaceData1 = (PTR)lpDDS;
|
|
hVSurface->pSurfaceData = (PTR)lpDDS2;
|
|
hVSurface->pSavedSurfaceData1 = NULL;
|
|
hVSurface->pSavedSurfaceData = NULL;
|
|
hVSurface->pPalette = NULL;
|
|
hVSurface->p16BPPPalette = NULL;
|
|
hVSurface->TransparentColor = FROMRGB( 0, 0, 0 );
|
|
hVSurface->RegionList = CreateList( DEFAULT_NUM_REGIONS, sizeof( VSURFACE_REGION ) );
|
|
hVSurface->fFlags = 0;
|
|
hVSurface->pClipper = NULL;
|
|
|
|
//
|
|
// Determine memory and other attributes of newly created surface
|
|
//
|
|
|
|
DDGetSurfaceDescription ( lpDDS2, &SurfaceDescription );
|
|
|
|
//
|
|
// Fail if create tried for video but it's in system
|
|
//
|
|
|
|
if ( VSurfaceDesc->fCreateFlags & VSURFACE_VIDEO_MEM_USAGE && SurfaceDescription.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY )
|
|
{
|
|
//
|
|
// Return failure due to not in video
|
|
//
|
|
|
|
DbgMessage( TOPIC_VIDEOSURFACE, DBG_LEVEL_2, String( "Failed to create Video Surface in video memory" ) );
|
|
DDReleaseSurface ( &lpDDS, &lpDDS2 );
|
|
MemFree( hVSurface );
|
|
return( NULL );
|
|
}
|
|
|
|
//
|
|
// Look for system memory
|
|
//
|
|
|
|
if ( SurfaceDescription.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY )
|
|
{
|
|
hVSurface->fFlags |= VSURFACE_SYSTEM_MEM_USAGE;
|
|
}
|
|
|
|
//
|
|
// Look for video memory
|
|
//
|
|
|
|
if ( SurfaceDescription.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY )
|
|
{
|
|
hVSurface->fFlags |= VSURFACE_VIDEO_MEM_USAGE;
|
|
}
|
|
|
|
//
|
|
// If in video memory, create backup surface
|
|
//
|
|
|
|
if ( hVSurface->fFlags & VSURFACE_VIDEO_MEM_USAGE )
|
|
{
|
|
SurfaceDescription.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
|
|
SurfaceDescription.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
|
SurfaceDescription.dwSize = sizeof(DDSURFACEDESC);
|
|
SurfaceDescription.dwWidth = usWidth;
|
|
SurfaceDescription.dwHeight = usHeight;
|
|
SurfaceDescription.ddpfPixelFormat = PixelFormat;
|
|
|
|
//
|
|
// Create Surface
|
|
//
|
|
|
|
DDCreateSurface ( lpDD2Object, &SurfaceDescription, &lpDDS, &lpDDS2 );
|
|
|
|
//
|
|
// Save surface to backup
|
|
//
|
|
|
|
hVSurface->pSavedSurfaceData1 = lpDDS;
|
|
hVSurface->pSavedSurfaceData = lpDDS2;
|
|
}
|
|
|
|
//
|
|
// Initialize surface with hImage , if given
|
|
//
|
|
|
|
if ( VSurfaceDesc->fCreateFlags & VSURFACE_CREATE_FROMFILE )
|
|
{
|
|
tempRect.iLeft = 0;
|
|
tempRect.iTop = 0;
|
|
tempRect.iRight = hImage->usWidth-1;
|
|
tempRect.iBottom = hImage->usHeight-1;
|
|
SetVideoSurfaceDataFromHImage( hVSurface, hImage, 0, 0, &tempRect );
|
|
|
|
//
|
|
// Set palette from himage
|
|
//
|
|
|
|
if ( hImage->ubBitDepth == 8 )
|
|
{
|
|
SetVideoSurfacePalette( hVSurface, hImage->pPalette );
|
|
}
|
|
|
|
//
|
|
// Delete himage object
|
|
//
|
|
|
|
DestroyImage( hImage );
|
|
}
|
|
|
|
//
|
|
// All is well
|
|
//
|
|
|
|
hVSurface->usHeight = usHeight;
|
|
hVSurface->usWidth = usWidth;
|
|
// BF: re-set bit depth (see above)
|
|
hVSurface->ubBitDepth = ubBitDepth > 16 ? 16 : ubBitDepth;
|
|
|
|
giMemUsedInSurfaces += ( hVSurface->usHeight * hVSurface->usWidth * ( hVSurface->ubBitDepth / 8 ) );
|
|
|
|
DbgMessage( TOPIC_VIDEOSURFACE, DBG_LEVEL_3, String("Success in Creating Video Surface" ) );
|
|
|
|
return( hVSurface );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Called when surface is lost, for the most part called by utility functions
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOLEAN RestoreVideoSurface( HVSURFACE hVSurface )
|
|
{
|
|
LPDIRECTDRAWSURFACE2 lpDDSurface;
|
|
LPDIRECTDRAWSURFACE2 lpBackupDDSurface;
|
|
RECT aRect;
|
|
|
|
Assert( hVSurface != NULL );
|
|
|
|
//
|
|
// Restore is only for VIDEO MEMORY - should check if VIDEO and QUIT if not
|
|
//
|
|
|
|
if ( !( hVSurface->fFlags & VSURFACE_VIDEO_MEM_USAGE ) )
|
|
{
|
|
//
|
|
// No second surfaace has been allocated, return failure
|
|
//
|
|
|
|
DbgMessage( TOPIC_VIDEOSURFACE, DBG_LEVEL_2, String("Failed to restore Video Surface surface" ) );
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// Check for valid secondary surface
|
|
//
|
|
|
|
if ( hVSurface->pSavedSurfaceData1 == NULL )
|
|
{
|
|
//
|
|
// No secondary surface available
|
|
//
|
|
|
|
DbgMessage( TOPIC_VIDEOSURFACE, DBG_LEVEL_2, String("Failure in retoring- no secondary surface found" ) );
|
|
return( FALSE );
|
|
}
|
|
|
|
// Restore primary surface
|
|
lpDDSurface = ( LPDIRECTDRAWSURFACE2 )hVSurface->pSurfaceData;
|
|
DDRestoreSurface( lpDDSurface );
|
|
|
|
// Blit backup surface data into primary
|
|
lpBackupDDSurface = ( LPDIRECTDRAWSURFACE2 )hVSurface->pSavedSurfaceData;
|
|
|
|
aRect.top = (int)0;
|
|
aRect.left = (int)0;
|
|
aRect.bottom = (int)hVSurface->usHeight;
|
|
aRect.right = (int)hVSurface->usWidth;
|
|
|
|
DDBltFastSurface( (LPDIRECTDRAWSURFACE2)hVSurface->pSavedSurfaceData, 0, 0, (LPDIRECTDRAWSURFACE2)hVSurface->pSurfaceData, &aRect, DDBLTFAST_NOCOLORKEY );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
// Lock must be followed by release
|
|
// Pitch MUST be used for all width calculations ( Pitch is in bytes )
|
|
// The time between Locking and unlocking must be minimal
|
|
BYTE *LockVideoSurfaceBuffer( HVSURFACE hVSurface, UINT32 *pPitch )
|
|
{
|
|
DDSURFACEDESC SurfaceDescription;
|
|
|
|
// Assertions
|
|
if ( hVSurface == NULL )
|
|
{
|
|
//int breakpoint = 0;
|
|
}
|
|
|
|
|
|
Assert( hVSurface != NULL );
|
|
Assert( pPitch != NULL );
|
|
|
|
|
|
DDLockSurface( (LPDIRECTDRAWSURFACE2)hVSurface->pSurfaceData, NULL, &SurfaceDescription, 0, NULL);
|
|
|
|
*pPitch = SurfaceDescription.lPitch;
|
|
|
|
return (BYTE *)SurfaceDescription.lpSurface;
|
|
}
|
|
|
|
void UnLockVideoSurfaceBuffer( HVSURFACE hVSurface )
|
|
{
|
|
Assert( hVSurface != NULL );
|
|
|
|
|
|
DDUnlockSurface( (LPDIRECTDRAWSURFACE2)hVSurface->pSurfaceData, NULL );
|
|
|
|
// Copy contents if surface is in video
|
|
if ( hVSurface->fFlags & VSURFACE_VIDEO_MEM_USAGE && !(hVSurface->fFlags & VSURFACE_RESERVED_SURFACE) )
|
|
{
|
|
UpdateBackupSurface( hVSurface );
|
|
}
|
|
}
|
|
|
|
// Given an HIMAGE object, blit imagery into existing Video Surface. Can be from 8->16 BPP
|
|
BOOLEAN SetVideoSurfaceDataFromHImage( HVSURFACE hVSurface, HIMAGE hImage, UINT16 usX, UINT16 usY, SGPRect *pSrcRect )
|
|
{
|
|
BYTE *pDest;
|
|
UINT32 fBufferBPP = 0;
|
|
UINT32 uiPitch;
|
|
UINT16 usPixelWidth;
|
|
SGPRect aRect;
|
|
|
|
// Assertions
|
|
Assert( hVSurface != NULL );
|
|
Assert( hImage != NULL );
|
|
|
|
// Get Size of hImage and determine if it can fit
|
|
CHECKF( hImage->usWidth >= hVSurface->usWidth );
|
|
CHECKF( hImage->usHeight >= hVSurface->usHeight );
|
|
|
|
// Check BPP and see if they are the same
|
|
if ( hImage->ubBitDepth != hVSurface->ubBitDepth )
|
|
{
|
|
// They are not the same, but we can go from 8->16 without much cost
|
|
if ( hImage->ubBitDepth == 8 && hVSurface->ubBitDepth == 16 )
|
|
{
|
|
fBufferBPP = BUFFER_16BPP;
|
|
}
|
|
else if ( (hImage->ubBitDepth == 24 || hImage->ubBitDepth == 32) && hVSurface->ubBitDepth == 16 )
|
|
{
|
|
// convert image to 16bpp
|
|
fBufferBPP = BUFFER_16BPP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Set buffer BPP
|
|
switch ( hImage->ubBitDepth )
|
|
{
|
|
case 8:
|
|
|
|
fBufferBPP = BUFFER_8BPP;
|
|
break;
|
|
|
|
case 16:
|
|
|
|
fBufferBPP = BUFFER_16BPP;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
Assert( fBufferBPP != 0 );
|
|
|
|
// Get surface buffer data
|
|
pDest = LockVideoSurfaceBuffer( hVSurface, &uiPitch );
|
|
|
|
// Effective width ( in PIXELS ) is Pitch ( in bytes ) converted to pitch ( IN PIXELS )
|
|
usPixelWidth = (UINT16)( uiPitch / ( hVSurface->ubBitDepth / 8 ) );
|
|
|
|
CHECKF( pDest != NULL );
|
|
|
|
// Blit Surface
|
|
// If rect is NULL, use entrie image size
|
|
if ( pSrcRect == NULL )
|
|
{
|
|
aRect.iLeft = 0;
|
|
aRect.iTop = 0;
|
|
aRect.iRight = hImage->usWidth;
|
|
aRect.iBottom = hImage->usHeight;
|
|
}
|
|
else
|
|
{
|
|
aRect.iLeft = pSrcRect->iLeft;
|
|
aRect.iTop = pSrcRect->iTop;
|
|
aRect.iRight = pSrcRect->iRight;
|
|
aRect.iBottom = pSrcRect->iBottom;
|
|
}
|
|
|
|
// This HIMAGE function will transparently copy buffer
|
|
if ( !CopyImageToBuffer( hImage, fBufferBPP, pDest, usPixelWidth, hVSurface->usHeight, usX, usY, &aRect ) )
|
|
{
|
|
DbgMessage( TOPIC_VIDEOSURFACE, DBG_LEVEL_2, String( "Error Occured Copying HIMAGE to HVSURFACE" ));
|
|
UnLockVideoSurfaceBuffer( hVSurface );
|
|
return( FALSE );
|
|
}
|
|
|
|
// All is OK
|
|
UnLockVideoSurfaceBuffer( hVSurface );
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
// Palette setting is expensive, need to set both DDPalette and create 16BPP palette
|
|
BOOLEAN SetVideoSurfacePalette( HVSURFACE hVSurface, SGPPaletteEntry *pSrcPalette )
|
|
{
|
|
|
|
Assert( hVSurface != NULL );
|
|
|
|
// Create palette object if not already done so
|
|
if ( hVSurface->pPalette == NULL )
|
|
{
|
|
DDCreatePalette( GetDirectDraw2Object(), (DDPCAPS_8BIT | DDPCAPS_ALLOW256), (LPPALETTEENTRY)(&pSrcPalette[0]), (LPDIRECTDRAWPALETTE*)&(hVSurface->pPalette), NULL);
|
|
|
|
// Set into surface
|
|
//DDSetSurfacePalette( (LPDIRECTDRAWSURFACE2)hVSurface->pSurfaceData, (LPDIRECTDRAWPALETTE)hVSurface->pPalette );
|
|
|
|
}
|
|
else
|
|
{
|
|
// Just Change entries
|
|
DDSetPaletteEntries( (LPDIRECTDRAWPALETTE)hVSurface->pPalette, 0, 0, 256, ( PALETTEENTRY*)pSrcPalette );
|
|
}
|
|
|
|
// Delete 16BPP Palette if one exists
|
|
if ( hVSurface->p16BPPPalette != NULL )
|
|
{
|
|
MemFree( hVSurface->p16BPPPalette );
|
|
hVSurface->p16BPPPalette = NULL;
|
|
}
|
|
|
|
// Create 16BPP Palette
|
|
hVSurface->p16BPPPalette = Create16BPPPalette( pSrcPalette );
|
|
|
|
DbgMessage(TOPIC_VIDEOSURFACE, DBG_LEVEL_3, String("Video Surface Palette change successfull" ));
|
|
return( TRUE );
|
|
}
|
|
|
|
// Transparency needs to take RGB value and find best fit and place it into DD Surface
|
|
// colorkey value.
|
|
BOOLEAN SetVideoSurfaceTransparencyColor( HVSURFACE hVSurface, COLORVAL TransColor )
|
|
{
|
|
DDCOLORKEY ColorKey;
|
|
DWORD fFlags = CLR_INVALID;
|
|
LPDIRECTDRAWSURFACE2 lpDDSurface;
|
|
|
|
// Assertions
|
|
Assert( hVSurface != NULL );
|
|
|
|
//Set trans color into Video Surface
|
|
hVSurface->TransparentColor = TransColor;
|
|
|
|
// Get surface pointer
|
|
lpDDSurface = (LPDIRECTDRAWSURFACE2)hVSurface->pSurfaceData;
|
|
CHECKF( lpDDSurface != NULL );
|
|
|
|
// Get right pixel format, based on bit depth
|
|
|
|
switch( hVSurface->ubBitDepth )
|
|
{
|
|
case 8:
|
|
|
|
// Use color directly
|
|
ColorKey.dwColorSpaceLowValue = TransColor;
|
|
ColorKey.dwColorSpaceHighValue = TransColor;
|
|
break;
|
|
|
|
case 16:
|
|
|
|
fFlags = Get16BPPColor( TransColor );
|
|
|
|
//fFlags now contains our closest match
|
|
ColorKey.dwColorSpaceLowValue = fFlags;
|
|
ColorKey.dwColorSpaceHighValue = ColorKey.dwColorSpaceLowValue;
|
|
break;
|
|
|
|
}
|
|
|
|
DDSetSurfaceColorKey( lpDDSurface, DDCKEY_SRCBLT, &ColorKey);
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN GetVSurfacePaletteEntries( HVSURFACE hVSurface, SGPPaletteEntry *pPalette )
|
|
{
|
|
CHECKF( hVSurface->pPalette != NULL );
|
|
|
|
DDGetPaletteEntries( (LPDIRECTDRAWPALETTE)hVSurface->pPalette, 0, 0, 256, (PALETTEENTRY*)pPalette );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN DeleteVideoSurfaceFromIndex( UINT32 uiIndex )
|
|
{
|
|
VSURFACE_NODE *curr;
|
|
|
|
#ifdef _DEBUG
|
|
gubVSDebugCode = DEBUGSTR_DELETEVIDEOSURFACEFROMINDEX;
|
|
CheckValidVSurfaceIndex( uiIndex );
|
|
#endif
|
|
|
|
curr = gpVSurfaceHead;
|
|
while( curr )
|
|
{
|
|
if( curr->uiIndex == uiIndex )
|
|
{ //Found the node, so detach it and delete it.
|
|
|
|
//Deallocate the memory for the video surface
|
|
DeleteVideoSurface( curr->hVSurface );
|
|
|
|
if( curr == gpVSurfaceHead )
|
|
{ //Advance the head, because we are going to remove the head node.
|
|
gpVSurfaceHead = gpVSurfaceHead->next;
|
|
}
|
|
if( curr == gpVSurfaceTail )
|
|
{ //Back up the tail, because we are going to remove the tail node.
|
|
gpVSurfaceTail = gpVSurfaceTail->prev;
|
|
}
|
|
//Detach the node from the vsurface list
|
|
if( curr->next )
|
|
{ //Make the prev node point to the next
|
|
curr->next->prev = curr->prev;
|
|
}
|
|
if( curr->prev )
|
|
{ //Make the next node point to the prev
|
|
curr->prev->next = curr->next;
|
|
}
|
|
//The node is now detached. Now deallocate it.
|
|
|
|
#ifdef SGP_VIDEO_DEBUGGING
|
|
if( curr->pName )
|
|
{
|
|
MemFree( curr->pName );
|
|
}
|
|
if( curr->pCode )
|
|
{
|
|
MemFree( curr->pCode );
|
|
}
|
|
#endif
|
|
|
|
MemFree( curr );
|
|
guiVSurfaceSize--;
|
|
return TRUE;
|
|
}
|
|
curr = curr->next;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Deletes all palettes, surfaces and region data
|
|
BOOLEAN DeleteVideoSurface( HVSURFACE hVSurface )
|
|
{
|
|
LPDIRECTDRAWSURFACE2 lpDDSurface;
|
|
|
|
// Assertions
|
|
CHECKF( hVSurface != NULL );
|
|
|
|
// Release palette
|
|
if ( hVSurface->pPalette != NULL )
|
|
{
|
|
DDReleasePalette( (LPDIRECTDRAWPALETTE)hVSurface->pPalette );
|
|
hVSurface->pPalette = NULL;
|
|
}
|
|
|
|
//if ( hVSurface->pClipper != NULL )
|
|
//{
|
|
// Release Clipper
|
|
// DDReleaseClipper( (LPDIRECTDRAWCLIPPER)hVSurface->pClipper );
|
|
//}
|
|
|
|
// Get surface pointer
|
|
lpDDSurface = (LPDIRECTDRAWSURFACE2)hVSurface->pSurfaceData;
|
|
|
|
// Release surface
|
|
if ( hVSurface->pSurfaceData1 != NULL )
|
|
{
|
|
DDReleaseSurface( (LPDIRECTDRAWSURFACE*)&hVSurface->pSurfaceData1, &lpDDSurface );
|
|
}
|
|
|
|
// Release backup surface
|
|
if ( hVSurface->pSavedSurfaceData != NULL )
|
|
{
|
|
DDReleaseSurface( (LPDIRECTDRAWSURFACE*)&hVSurface->pSavedSurfaceData1,
|
|
(LPDIRECTDRAWSURFACE2*)&hVSurface->pSavedSurfaceData );
|
|
}
|
|
|
|
// Release region data
|
|
DeleteList( hVSurface->RegionList );
|
|
|
|
//If there is a 16bpp palette, free it
|
|
if( hVSurface->p16BPPPalette != NULL )
|
|
{
|
|
MemFree( hVSurface->p16BPPPalette );
|
|
hVSurface->p16BPPPalette = NULL;
|
|
}
|
|
|
|
giMemUsedInSurfaces -= ( hVSurface->usHeight * hVSurface->usWidth * ( hVSurface->ubBitDepth / 8 ) );
|
|
|
|
// Release object
|
|
MemFree( hVSurface );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
// ********************************************************
|
|
//
|
|
// Clipper manipulation functions
|
|
//
|
|
// ********************************************************
|
|
|
|
BOOLEAN SetClipList( HVSURFACE hVSurface, SGPRect *RegionData, UINT16 usNumRegions )
|
|
{
|
|
RGNDATA *pRgnData;
|
|
UINT16 cnt;
|
|
RECT aRect;
|
|
LPDIRECTDRAW2 lpDD2Object;
|
|
|
|
// Get Direct Draw Object
|
|
lpDD2Object = GetDirectDraw2Object( );
|
|
|
|
// Assertions
|
|
Assert( hVSurface != NULL );
|
|
Assert( RegionData != NULL );
|
|
|
|
// Varifications
|
|
CHECKF( usNumRegions > 0 );
|
|
|
|
// If Clipper already created, release
|
|
if ( hVSurface->pClipper != NULL )
|
|
{
|
|
// Release Clipper
|
|
DDReleaseClipper( (LPDIRECTDRAWCLIPPER)hVSurface->pClipper );
|
|
}
|
|
|
|
// Create Clipper Object
|
|
DDCreateClipper( lpDD2Object, 0, (LPDIRECTDRAWCLIPPER*)&(hVSurface->pClipper) );
|
|
|
|
// Allocate region data
|
|
pRgnData = ( LPRGNDATA )MemAlloc( sizeof( RGNDATAHEADER) + ( usNumRegions * sizeof( RECT ) ) );
|
|
CHECKF( pRgnData );
|
|
|
|
// Setup header
|
|
pRgnData->rdh.dwSize = sizeof( RGNDATA );
|
|
pRgnData->rdh.iType = RDH_RECTANGLES;
|
|
pRgnData->rdh.nCount = usNumRegions;
|
|
pRgnData->rdh.nRgnSize = usNumRegions * sizeof( RECT );
|
|
pRgnData->rdh.rcBound.top = 0;
|
|
pRgnData->rdh.rcBound.left = 0;
|
|
pRgnData->rdh.rcBound.bottom = (int)hVSurface->usHeight;
|
|
pRgnData->rdh.rcBound.right = (int)hVSurface->usWidth;
|
|
|
|
// Copy rectangles into region
|
|
for ( cnt = 0; cnt < usNumRegions; cnt++ )
|
|
{
|
|
aRect.top = (UINT32)RegionData[ cnt ].iTop;
|
|
aRect.left = (UINT32)RegionData[ cnt ].iLeft;
|
|
aRect.bottom = (UINT32)RegionData[ cnt ].iBottom;
|
|
aRect.right = (UINT32)RegionData[ cnt ].iRight;
|
|
|
|
memcpy( pRgnData + sizeof( RGNDATAHEADER) + ( cnt * sizeof( RECT ) ), &aRect, sizeof( RECT ) );
|
|
}
|
|
|
|
// Set items into clipper
|
|
DDSetClipperList( (LPDIRECTDRAWCLIPPER)hVSurface->pClipper, pRgnData, 0 );
|
|
|
|
// Set Clipper into Surface
|
|
DDSetClipper( (LPDIRECTDRAWSURFACE2)hVSurface->pSurfaceData, (LPDIRECTDRAWCLIPPER)hVSurface->pClipper );
|
|
|
|
// Delete region data
|
|
MemFree( pRgnData );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
// ********************************************************
|
|
//
|
|
// Region manipulation functions
|
|
//
|
|
// ********************************************************
|
|
|
|
BOOLEAN GetNumRegions( HVSURFACE hVSurface , UINT32 *puiNumRegions )
|
|
{
|
|
Assert( hVSurface );
|
|
|
|
*puiNumRegions = ListSize( hVSurface->RegionList );
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
BOOLEAN AddVSurfaceRegion( HVSURFACE hVSurface, VSURFACE_REGION *pNewRegion )
|
|
{
|
|
Assert( hVSurface != NULL );
|
|
Assert( pNewRegion != NULL );
|
|
|
|
// Add new region to list
|
|
hVSurface->RegionList = AddtoList( hVSurface->RegionList, pNewRegion, ListSize( hVSurface->RegionList ) );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
// Add a group of regions
|
|
BOOLEAN AddVSurfaceRegions( HVSURFACE hVSurface, VSURFACE_REGION **ppNewRegions, UINT16 uiNumRegions )
|
|
{
|
|
UINT16 cnt;
|
|
|
|
Assert( hVSurface != NULL );
|
|
Assert( ppNewRegions != NULL );
|
|
|
|
for ( cnt = 0; cnt < uiNumRegions; cnt++ )
|
|
{
|
|
AddVSurfaceRegion( hVSurface, ppNewRegions[ cnt ] );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN RemoveVSurfaceRegion( HVSURFACE hVSurface, UINT16 usIndex )
|
|
{
|
|
VSURFACE_REGION aRegion;
|
|
|
|
Assert( hVSurface != NULL );
|
|
|
|
return( RemfromList( hVSurface->RegionList, &aRegion, usIndex ) );
|
|
|
|
}
|
|
|
|
BOOLEAN ClearAllVSurfaceRegions( HVSURFACE hVSurface )
|
|
{
|
|
UINT32 uiListSize;
|
|
|
|
Assert( hVSurface != NULL );
|
|
|
|
uiListSize = ListSize( hVSurface->RegionList );
|
|
|
|
for ( INT32 cnt = uiListSize - 1; cnt >= 0; cnt-- )
|
|
{
|
|
RemoveVSurfaceRegion( hVSurface, (UINT16)cnt );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN GetVSurfaceRegion( HVSURFACE hVSurface, UINT16 usIndex, VSURFACE_REGION *aRegion )
|
|
{
|
|
Assert( hVSurface != NULL );
|
|
|
|
if ( !PeekList( hVSurface->RegionList, aRegion, usIndex ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN GetVSurfaceRect( HVSURFACE hVSurface, RECT *pRect)
|
|
{
|
|
Assert( hVSurface != NULL );
|
|
Assert( pRect != NULL );
|
|
|
|
pRect->left=0;
|
|
pRect->top=0;
|
|
pRect->right=hVSurface->usWidth;
|
|
pRect->bottom=hVSurface->usHeight;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN ReplaceVSurfaceRegion( HVSURFACE hVSurface , UINT16 usIndex, VSURFACE_REGION *aRegion )
|
|
{
|
|
VSURFACE_REGION OldRegion;
|
|
|
|
Assert( hVSurface != NULL );
|
|
|
|
// Validate index given
|
|
if ( !PeekList( hVSurface->RegionList, &OldRegion, usIndex ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// Replace information
|
|
hVSurface->RegionList = AddtoList( hVSurface->RegionList, aRegion, usIndex );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN AddVSurfaceRegionAtIndex( HVSURFACE hVSurface, UINT16 usIndex, VSURFACE_REGION *pNewRegion )
|
|
{
|
|
Assert( hVSurface != NULL );
|
|
Assert( pNewRegion != NULL );
|
|
|
|
// Add new region to list
|
|
hVSurface->RegionList = AddtoList( hVSurface->RegionList, pNewRegion, usIndex );
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
// *******************************************************************
|
|
//
|
|
// Blitting Functions
|
|
//
|
|
// *******************************************************************
|
|
|
|
// Blt will use DD Blt or BltFast depending on flags.
|
|
// Will drop down into user-defined blitter if 8->16 BPP blitting is being done
|
|
|
|
BOOLEAN BltVideoSurfaceToVideoSurface( HVSURFACE hDestVSurface, HVSURFACE hSrcVSurface, UINT16 usIndex, INT32 iDestX, INT32 iDestY, INT32 fBltFlags, blt_vs_fx *pBltFx )
|
|
{
|
|
VSURFACE_REGION aRegion;
|
|
RECT SrcRect, DestRect;
|
|
UINT8 *pSrcSurface8, *pDestSurface8;
|
|
UINT16 *pDestSurface16, *pSrcSurface16;
|
|
UINT32 uiSrcPitch, uiDestPitch, uiWidth, uiHeight;
|
|
|
|
// Assertions
|
|
Assert( hDestVSurface != NULL );
|
|
|
|
// Check that both region and subrect are not given
|
|
if ((fBltFlags&VS_BLT_SRCREGION) && (fBltFlags&VS_BLT_SRCSUBRECT))
|
|
{
|
|
DbgMessage(TOPIC_VIDEOSURFACE, DBG_LEVEL_2, String( "Inconsistant blit flags given" ));
|
|
return( FALSE );
|
|
}
|
|
|
|
// Check for dest src options
|
|
if ( fBltFlags & VS_BLT_DESTREGION )
|
|
{
|
|
CHECKF( pBltFx != NULL );
|
|
CHECKF( GetVSurfaceRegion( hDestVSurface, pBltFx->DestRegion, &aRegion ) );
|
|
|
|
// Set starting coordinates from destination region
|
|
iDestY = aRegion.RegionCoords.iTop;
|
|
iDestX = aRegion.RegionCoords.iLeft;
|
|
}
|
|
|
|
// Check for fill, if true, fill entire region with color
|
|
if ( fBltFlags & VS_BLT_COLORFILL )
|
|
{
|
|
return( FillSurface( hDestVSurface, pBltFx ) );
|
|
}
|
|
|
|
// Check for colorfill rectangle
|
|
if ( fBltFlags & VS_BLT_COLORFILLRECT )
|
|
{
|
|
return( FillSurfaceRect( hDestVSurface, pBltFx ) );
|
|
}
|
|
|
|
// Check for source coordinate options - from region, specific rect or full src dimensions
|
|
do
|
|
{
|
|
// Get Region from index, if specified
|
|
if ( fBltFlags & VS_BLT_SRCREGION )
|
|
{
|
|
CHECKF( GetVSurfaceRegion( hSrcVSurface, usIndex, &aRegion ) )
|
|
|
|
SrcRect.top = (int)aRegion.RegionCoords.iTop;
|
|
SrcRect.left = (int)aRegion.RegionCoords.iLeft;
|
|
SrcRect.bottom = (int)aRegion.RegionCoords.iBottom;
|
|
SrcRect.right = (int)aRegion.RegionCoords.iRight;
|
|
break;
|
|
}
|
|
|
|
// Use SUBRECT if specified
|
|
if ( fBltFlags & VS_BLT_SRCSUBRECT )
|
|
{
|
|
SGPRect aSubRect;
|
|
|
|
CHECKF( pBltFx != NULL );
|
|
|
|
aSubRect = pBltFx->SrcRect;
|
|
|
|
SrcRect.top = (int)aSubRect.iTop;
|
|
SrcRect.left = (int)aSubRect.iLeft;
|
|
SrcRect.bottom = (int)aSubRect.iBottom;
|
|
SrcRect.right = (int)aSubRect.iRight;
|
|
|
|
break;
|
|
}
|
|
|
|
// Here, use default, which is entire Video Surface
|
|
// Check Sizes, SRC size MUST be <= DEST size
|
|
if ( hDestVSurface->usHeight < hSrcVSurface->usHeight )
|
|
{
|
|
DbgMessage(TOPIC_VIDEOSURFACE, DBG_LEVEL_2, String( "Incompatible height size given in Video Surface blit" ));
|
|
return( FALSE );
|
|
}
|
|
if ( hDestVSurface->usWidth < hSrcVSurface->usWidth )
|
|
{
|
|
DbgMessage(TOPIC_VIDEOSURFACE, DBG_LEVEL_2, String( "Incompatible height size given in Video Surface blit" ));
|
|
return( FALSE );
|
|
}
|
|
|
|
SrcRect.top = (int)0;
|
|
SrcRect.left = (int)0;
|
|
SrcRect.bottom = (int)hSrcVSurface->usHeight;
|
|
SrcRect.right = (int)hSrcVSurface->usWidth;
|
|
|
|
} while( FALSE );
|
|
|
|
// Once here, assert valid Src
|
|
Assert( hSrcVSurface != NULL );
|
|
|
|
// clipping -- added by DB
|
|
GetVSurfaceRect( hDestVSurface, &DestRect);
|
|
uiWidth=SrcRect.right-SrcRect.left;
|
|
uiHeight=SrcRect.bottom-SrcRect.top;
|
|
|
|
// check for position entirely off the screen
|
|
if(iDestX >= DestRect.right)
|
|
return(FALSE);
|
|
if(iDestY >= DestRect.bottom)
|
|
return(FALSE);
|
|
if((iDestX+(INT32)uiWidth) < (INT32)DestRect.left)
|
|
return(FALSE);
|
|
if((iDestY+(INT32)uiHeight) < (INT32)DestRect.top)
|
|
return(FALSE);
|
|
|
|
// DB The mirroring stuff has to do it's own clipping because
|
|
// it needs to invert some of the numbers
|
|
if(!(fBltFlags & VS_BLT_MIRROR_Y))
|
|
{
|
|
if((iDestX+(INT32)uiWidth) >= (INT32)DestRect.right)
|
|
{
|
|
SrcRect.right-=((iDestX+uiWidth)-DestRect.right);
|
|
uiWidth-=((iDestX+uiWidth)-DestRect.right);
|
|
}
|
|
if((iDestY+(INT32)uiHeight) >= (INT32)DestRect.bottom)
|
|
{
|
|
SrcRect.bottom-=((iDestY+uiHeight)-DestRect.bottom);
|
|
uiHeight-=((iDestY+uiHeight)-DestRect.bottom);
|
|
}
|
|
if(iDestX < DestRect.left)
|
|
{
|
|
SrcRect.left+=(DestRect.left-iDestX);
|
|
uiWidth-=(DestRect.left-iDestX);
|
|
iDestX=DestRect.left;
|
|
}
|
|
if(iDestY < (INT32)DestRect.top)
|
|
{
|
|
SrcRect.top+=(DestRect.top-iDestY);
|
|
uiHeight-=(DestRect.top-iDestY);
|
|
iDestY=DestRect.top;
|
|
}
|
|
}
|
|
|
|
// Send dest position, rectangle, etc to DD bltfast function
|
|
// First check BPP values for compatibility
|
|
if ( hDestVSurface->ubBitDepth == 16 && hSrcVSurface->ubBitDepth == 16 )
|
|
{
|
|
if(fBltFlags & VS_BLT_MIRROR_Y)
|
|
{
|
|
if((pSrcSurface16=(UINT16 *)LockVideoSurfaceBuffer(hSrcVSurface, &uiSrcPitch))==NULL)
|
|
{
|
|
DbgMessage(TOPIC_VIDEOSURFACE, DBG_LEVEL_2, String( "Failed on lock of 16BPP surface for blitting" ));
|
|
return(FALSE);
|
|
}
|
|
|
|
if((pDestSurface16=(UINT16 *)LockVideoSurfaceBuffer(hDestVSurface, &uiDestPitch))==NULL)
|
|
{
|
|
UnLockVideoSurfaceBuffer(hSrcVSurface);
|
|
DbgMessage(TOPIC_VIDEOSURFACE, DBG_LEVEL_2, String( "Failed on lock of 16BPP dest surface for blitting" ));
|
|
return(FALSE);
|
|
}
|
|
|
|
Blt16BPPTo16BPPMirror(pDestSurface16, uiDestPitch, pSrcSurface16, uiSrcPitch, iDestX, iDestY, SrcRect.left, SrcRect.top, uiWidth, uiHeight);
|
|
UnLockVideoSurfaceBuffer(hSrcVSurface);
|
|
UnLockVideoSurfaceBuffer(hDestVSurface);
|
|
return(TRUE);
|
|
}
|
|
// For testing with non-DDraw blitting, uncomment to test -- DB
|
|
|
|
CHECKF( BltVSurfaceUsingDD( hDestVSurface, hSrcVSurface, fBltFlags, iDestX, iDestY, &SrcRect ) );
|
|
|
|
}
|
|
else if ( hDestVSurface->ubBitDepth == 8 && hSrcVSurface->ubBitDepth == 8 )
|
|
{
|
|
if((pSrcSurface8=(UINT8 *)LockVideoSurfaceBuffer(hSrcVSurface, &uiSrcPitch))==NULL)
|
|
{
|
|
DbgMessage(TOPIC_VIDEOSURFACE, DBG_LEVEL_2, String( "Failed on lock of 8BPP surface for blitting" ));
|
|
return(FALSE);
|
|
}
|
|
|
|
if((pDestSurface8=(UINT8 *)LockVideoSurfaceBuffer(hDestVSurface, &uiDestPitch))==NULL)
|
|
{
|
|
UnLockVideoSurfaceBuffer(hSrcVSurface);
|
|
DbgMessage(TOPIC_VIDEOSURFACE, DBG_LEVEL_2, String( "Failed on lock of 8BPP dest surface for blitting" ));
|
|
return(FALSE);
|
|
}
|
|
|
|
//Blt8BPPDataTo8BPPBuffer( UINT8 *pBuffer, UINT32 uiDestPitchBYTES, HVOBJECT hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex );
|
|
Blt8BPPTo8BPP(pDestSurface8, uiDestPitch, pSrcSurface8, uiSrcPitch, iDestX, iDestY, SrcRect.left, SrcRect.top, uiWidth, uiHeight);
|
|
UnLockVideoSurfaceBuffer(hSrcVSurface);
|
|
UnLockVideoSurfaceBuffer(hDestVSurface);
|
|
return(TRUE);
|
|
}
|
|
else
|
|
{
|
|
DbgMessage(TOPIC_VIDEOSURFACE, DBG_LEVEL_2, String( "Incompatible BPP values with src and dest Video Surfaces for blitting" ));
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
// ******************************************************************************************
|
|
//
|
|
// UTILITY FUNCTIONS
|
|
//
|
|
// ******************************************************************************************
|
|
|
|
// Blt to backup buffer
|
|
BOOLEAN UpdateBackupSurface( HVSURFACE hVSurface )
|
|
{
|
|
RECT aRect;
|
|
|
|
// Assertions
|
|
Assert( hVSurface != NULL );
|
|
|
|
// Validations
|
|
CHECKF( hVSurface->pSavedSurfaceData != NULL );
|
|
|
|
aRect.top = (int)0;
|
|
aRect.left = (int)0;
|
|
aRect.bottom = (int)hVSurface->usHeight;
|
|
aRect.right = (int)hVSurface->usWidth;
|
|
|
|
// Copy all contents into backup buffer
|
|
DDBltFastSurface( (LPDIRECTDRAWSURFACE2)hVSurface->pSurfaceData, 0, 0, (LPDIRECTDRAWSURFACE2)hVSurface->pSavedSurfaceData, &aRect, DDBLTFAST_NOCOLORKEY );
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
|
|
// *****************************************************************************
|
|
//
|
|
// Private DirectDraw manipulation functions
|
|
//
|
|
// *****************************************************************************
|
|
|
|
LPDIRECTDRAWSURFACE2 GetVideoSurfaceDDSurface( HVSURFACE hVSurface )
|
|
{
|
|
Assert( hVSurface != NULL );
|
|
|
|
return( (LPDIRECTDRAWSURFACE2) hVSurface->pSurfaceData );
|
|
}
|
|
|
|
LPDIRECTDRAWSURFACE GetVideoSurfaceDDSurfaceOne( HVSURFACE hVSurface )
|
|
{
|
|
Assert( hVSurface != NULL );
|
|
|
|
return( (LPDIRECTDRAWSURFACE) hVSurface->pSurfaceData1 );
|
|
}
|
|
|
|
|
|
LPDIRECTDRAWPALETTE GetVideoSurfaceDDPalette( HVSURFACE hVSurface )
|
|
{
|
|
Assert( hVSurface != NULL );
|
|
|
|
return( (LPDIRECTDRAWPALETTE) hVSurface->pPalette );
|
|
}
|
|
|
|
HVSURFACE CreateVideoSurfaceFromDDSurface( LPDIRECTDRAWSURFACE2 lpDDSurface )
|
|
{
|
|
// Create Video Surface
|
|
DDPIXELFORMAT PixelFormat;
|
|
HVSURFACE hVSurface;
|
|
DDSURFACEDESC DDSurfaceDesc;
|
|
LPDIRECTDRAWPALETTE pDDPalette;
|
|
SGPPaletteEntry SGPPalette[ 256 ];
|
|
HRESULT ReturnCode;
|
|
|
|
|
|
// Allocate Video Surface struct
|
|
hVSurface = (HVSURFACE) MemAlloc( sizeof( SGPVSurface ) );
|
|
|
|
// Set values based on DD Surface given
|
|
DDGetSurfaceDescription ( lpDDSurface, &DDSurfaceDesc );
|
|
PixelFormat = DDSurfaceDesc.ddpfPixelFormat;
|
|
|
|
hVSurface->usHeight = (UINT16)DDSurfaceDesc.dwHeight;
|
|
hVSurface->usWidth = (UINT16)DDSurfaceDesc.dwWidth;
|
|
hVSurface->ubBitDepth = (UINT8)PixelFormat.dwRGBBitCount;
|
|
hVSurface->pSurfaceData = (PTR)lpDDSurface;
|
|
hVSurface->pSurfaceData1 = NULL;
|
|
hVSurface->pSavedSurfaceData = NULL;
|
|
hVSurface->RegionList = CreateList( DEFAULT_NUM_REGIONS, sizeof( VSURFACE_REGION ) );
|
|
hVSurface->fFlags = 0;
|
|
|
|
// Get and Set palette, if attached, allow to fail
|
|
ReturnCode = IDirectDrawSurface2_GetPalette( lpDDSurface, &pDDPalette );
|
|
|
|
if ( ReturnCode == DD_OK )
|
|
{
|
|
// Set 8-bit Palette and 16 BPP palette
|
|
hVSurface->pPalette = pDDPalette;
|
|
|
|
// Create 16-BPP Palette
|
|
DDGetPaletteEntries( pDDPalette, 0, 0, 256, ( LPPALETTEENTRY )SGPPalette );
|
|
hVSurface->p16BPPPalette = Create16BPPPalette( SGPPalette );
|
|
}
|
|
else
|
|
{
|
|
hVSurface->pPalette = NULL;
|
|
hVSurface->p16BPPPalette = NULL;
|
|
}
|
|
// Set meory flags
|
|
if ( DDSurfaceDesc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY )
|
|
{
|
|
hVSurface->fFlags |= VSURFACE_SYSTEM_MEM_USAGE;
|
|
}
|
|
|
|
if ( DDSurfaceDesc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY )
|
|
{
|
|
hVSurface->fFlags |= VSURFACE_VIDEO_MEM_USAGE;
|
|
}
|
|
|
|
// All is well
|
|
DbgMessage( TOPIC_VIDEOSURFACE, DBG_LEVEL_0, String("Success in Creating Video Surface from DD Surface" ) );
|
|
|
|
return( hVSurface );
|
|
}
|
|
|
|
HVSURFACE GetPrimaryVideoSurface( )
|
|
{
|
|
return( ghPrimary );
|
|
}
|
|
|
|
HVSURFACE GetBackBufferVideoSurface( )
|
|
{
|
|
return( ghBackBuffer );
|
|
}
|
|
|
|
HVSURFACE GetFrameBufferVideoSurface( )
|
|
{
|
|
return( ghFrameBuffer );
|
|
}
|
|
|
|
HVSURFACE GetMouseBufferVideoSurface( )
|
|
{
|
|
return( ghMouseBuffer );
|
|
}
|
|
|
|
|
|
// UTILITY FUNCTIONS FOR BLITTING
|
|
|
|
BOOLEAN ClipReleatedSrcAndDestRectangles( HVSURFACE hDestVSurface, HVSURFACE hSrcVSurface, RECT *DestRect, RECT *SrcRect )
|
|
{
|
|
|
|
Assert( hDestVSurface != NULL );
|
|
Assert( hSrcVSurface != NULL );
|
|
|
|
// Check for invalid start positions and clip by ignoring blit
|
|
if ( DestRect->left >= hDestVSurface->usWidth || DestRect->top >= hDestVSurface->usHeight )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( SrcRect->left >= hSrcVSurface->usWidth || SrcRect->top >= hSrcVSurface->usHeight )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// For overruns
|
|
// Clip destination rectangles
|
|
if ( DestRect->right > hDestVSurface->usWidth )
|
|
{
|
|
// Both have to be modified or by default streching occurs
|
|
DestRect->right = hDestVSurface->usWidth;
|
|
SrcRect->right = SrcRect->left + ( DestRect->right - DestRect->left );
|
|
}
|
|
if ( DestRect->bottom > hDestVSurface->usHeight )
|
|
{
|
|
// Both have to be modified or by default streching occurs
|
|
DestRect->bottom = hDestVSurface->usHeight;
|
|
SrcRect->bottom = SrcRect->top + ( DestRect->bottom - DestRect->top );
|
|
}
|
|
|
|
// Clip src rectangles
|
|
if ( SrcRect->right > hSrcVSurface->usWidth )
|
|
{
|
|
// Both have to be modified or by default streching occurs
|
|
SrcRect->right = hSrcVSurface->usWidth;
|
|
DestRect->right = DestRect->left + ( SrcRect->right - SrcRect->left );
|
|
}
|
|
if ( SrcRect->bottom > hSrcVSurface->usHeight )
|
|
{
|
|
// Both have to be modified or by default streching occurs
|
|
SrcRect->bottom = hSrcVSurface->usHeight;
|
|
DestRect->bottom = DestRect->top + ( SrcRect->bottom - SrcRect->top );
|
|
}
|
|
|
|
// For underruns
|
|
// Clip destination rectangles
|
|
if ( DestRect->left < 0 )
|
|
{
|
|
// Both have to be modified or by default streching occurs
|
|
DestRect->left = 0;
|
|
SrcRect->left = SrcRect->right - ( DestRect->right - DestRect->left );
|
|
}
|
|
if ( DestRect->top < 0 )
|
|
{
|
|
// Both have to be modified or by default streching occurs
|
|
DestRect->top = 0;
|
|
SrcRect->top = SrcRect->bottom - ( DestRect->bottom - DestRect->top );
|
|
}
|
|
|
|
// Clip src rectangles
|
|
if ( SrcRect->left < 0 )
|
|
{
|
|
// Both have to be modified or by default streching occurs
|
|
SrcRect->left = 0;
|
|
DestRect->left = DestRect->right - ( SrcRect->right - SrcRect->left );
|
|
}
|
|
if ( SrcRect->top < 0 )
|
|
{
|
|
// Both have to be modified or by default streching occurs
|
|
SrcRect->top = 0;
|
|
DestRect->top = DestRect->bottom - ( SrcRect->bottom - SrcRect->top );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN FillSurface( HVSURFACE hDestVSurface, blt_vs_fx *pBltFx )
|
|
{
|
|
DDBLTFX BlitterFX;
|
|
|
|
Assert( hDestVSurface != NULL );
|
|
CHECKF( pBltFx != NULL );
|
|
|
|
BlitterFX.dwSize = sizeof( DDBLTFX );
|
|
BlitterFX.dwFillColor = pBltFx->ColorFill;
|
|
|
|
DDBltSurface( (LPDIRECTDRAWSURFACE2)hDestVSurface->pSurfaceData, NULL, NULL, NULL, DDBLT_COLORFILL, &BlitterFX );
|
|
|
|
if ( hDestVSurface->fFlags & VSURFACE_VIDEO_MEM_USAGE && !(hDestVSurface->fFlags & VSURFACE_RESERVED_SURFACE) )
|
|
{
|
|
UpdateBackupSurface( hDestVSurface );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN FillSurfaceRect( HVSURFACE hDestVSurface, blt_vs_fx *pBltFx )
|
|
{
|
|
DDBLTFX BlitterFX;
|
|
|
|
Assert( hDestVSurface != NULL );
|
|
CHECKF( pBltFx != NULL );
|
|
|
|
BlitterFX.dwSize = sizeof( DDBLTFX );
|
|
BlitterFX.dwFillColor = pBltFx->ColorFill;
|
|
|
|
DDBltSurface( (LPDIRECTDRAWSURFACE2)hDestVSurface->pSurfaceData, (LPRECT)&(pBltFx->FillRect), NULL, NULL, DDBLT_COLORFILL, &BlitterFX );
|
|
|
|
if ( hDestVSurface->fFlags & VSURFACE_VIDEO_MEM_USAGE && !(hDestVSurface->fFlags & VSURFACE_RESERVED_SURFACE) )
|
|
{
|
|
UpdateBackupSurface( hDestVSurface );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN BltVSurfaceUsingDD( HVSURFACE hDestVSurface, HVSURFACE hSrcVSurface, UINT32 fBltFlags, INT32 iDestX, INT32 iDestY, RECT *SrcRect )
|
|
{
|
|
UINT32 uiDDFlags;
|
|
RECT DestRect;
|
|
|
|
// Blit using the correct blitter
|
|
if ( fBltFlags & VS_BLT_FAST )
|
|
{
|
|
|
|
// Validations
|
|
CHECKF( iDestX >= 0 );
|
|
CHECKF( iDestY >= 0 );
|
|
|
|
// Default flags
|
|
uiDDFlags = 0;
|
|
|
|
// Convert flags into DD flags, ( for transparency use, etc )
|
|
if ( fBltFlags & VS_BLT_USECOLORKEY )
|
|
{
|
|
uiDDFlags |= DDBLTFAST_SRCCOLORKEY;
|
|
}
|
|
|
|
// Convert flags into DD flags, ( for transparency use, etc )
|
|
if ( fBltFlags & VS_BLT_USEDESTCOLORKEY )
|
|
{
|
|
uiDDFlags |= DDBLTFAST_DESTCOLORKEY;
|
|
}
|
|
|
|
if ( uiDDFlags == 0 )
|
|
{
|
|
// Default here is no colorkey
|
|
uiDDFlags = DDBLTFAST_NOCOLORKEY;
|
|
}
|
|
|
|
DDBltFastSurface( (LPDIRECTDRAWSURFACE2)hDestVSurface->pSurfaceData, iDestX, iDestY, (LPDIRECTDRAWSURFACE2)hSrcVSurface->pSurfaceData, SrcRect, uiDDFlags );
|
|
|
|
}
|
|
else
|
|
{
|
|
// Normal, specialized blit for clipping, etc
|
|
|
|
// Default flags
|
|
uiDDFlags = DDBLT_WAIT;
|
|
|
|
// Convert flags into DD flags, ( for transparency use, etc )
|
|
if ( fBltFlags & VS_BLT_USECOLORKEY )
|
|
{
|
|
uiDDFlags |= DDBLT_KEYSRC;
|
|
}
|
|
|
|
// Setup dest rectangle
|
|
DestRect.top = (int)iDestY;
|
|
DestRect.left = (int)iDestX;
|
|
DestRect.bottom = (int)iDestY + ( SrcRect->bottom - SrcRect->top );
|
|
DestRect.right = (int)iDestX + ( SrcRect->right - SrcRect->left );
|
|
|
|
// Do Clipping of rectangles
|
|
if ( !ClipReleatedSrcAndDestRectangles( hDestVSurface, hSrcVSurface, &DestRect, SrcRect ) )
|
|
{
|
|
// Returns false because dest start is > dest size
|
|
return( TRUE );
|
|
}
|
|
|
|
// Check values for 0 size
|
|
if ( DestRect.top == DestRect.bottom || DestRect.right == DestRect.left )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
// Check for -ve values
|
|
|
|
|
|
|
|
DDBltSurface( (LPDIRECTDRAWSURFACE2)hDestVSurface->pSurfaceData, &DestRect, (LPDIRECTDRAWSURFACE2)hSrcVSurface->pSurfaceData,
|
|
SrcRect, uiDDFlags, NULL );
|
|
|
|
}
|
|
|
|
// Update backup surface with new data
|
|
if ( hDestVSurface->fFlags & VSURFACE_VIDEO_MEM_USAGE && !(hDestVSurface->fFlags & VSURFACE_RESERVED_SURFACE) )
|
|
{
|
|
UpdateBackupSurface( hDestVSurface );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN Blt16BPPBufferShadowRectAlternateTable(UINT16 *pBuffer, UINT32 uiDestPitchBYTES, SGPRect *area);
|
|
|
|
|
|
|
|
BOOLEAN InternalShadowVideoSurfaceRect( UINT32 uiDestVSurface, INT32 X1, INT32 Y1, INT32 X2, INT32 Y2, BOOLEAN fLowPercentShadeTable )
|
|
{
|
|
UINT16 *pBuffer;
|
|
UINT32 uiPitch;
|
|
SGPRect area;
|
|
HVSURFACE hVSurface;
|
|
|
|
|
|
// CLIP IT!
|
|
// FIRST GET SURFACE
|
|
|
|
//
|
|
// Get Video Surface
|
|
//
|
|
#ifdef _DEBUG
|
|
gubVSDebugCode = DEBUGSTR_SHADOWVIDEOSURFACERECT;
|
|
#endif
|
|
CHECKF( GetVideoSurface( &hVSurface, uiDestVSurface ) );
|
|
|
|
if ( X1 < 0 )
|
|
X1 = 0;
|
|
|
|
if ( X2 < 0 )
|
|
return( FALSE );
|
|
|
|
if ( Y2 < 0 )
|
|
return( FALSE );
|
|
|
|
if ( Y1 < 0 )
|
|
Y1 = 0;
|
|
|
|
if ( X2 >= hVSurface->usWidth )
|
|
X2 = hVSurface->usWidth-1;
|
|
|
|
if ( Y2 >= hVSurface->usHeight )
|
|
Y2 = hVSurface->usHeight-1;
|
|
|
|
if ( X1 >= hVSurface->usWidth )
|
|
return( FALSE );
|
|
|
|
if ( Y1 >= hVSurface->usHeight )
|
|
return( FALSE );
|
|
|
|
if ( ( X2 - X1 ) <= 0 )
|
|
return( FALSE );
|
|
|
|
if ( ( Y2 - Y1 ) <= 0 )
|
|
return( FALSE );
|
|
|
|
|
|
area.iTop=Y1;
|
|
area.iBottom=Y2;
|
|
area.iLeft=X1;
|
|
area.iRight=X2;
|
|
|
|
|
|
// Lock video surface
|
|
pBuffer = (UINT16*)LockVideoSurface( uiDestVSurface, &uiPitch );
|
|
//UnLockVideoSurface( uiDestVSurface );
|
|
|
|
if ( pBuffer == NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( !fLowPercentShadeTable )
|
|
{
|
|
// Now we have the video object and surface, call the shadow function
|
|
if(!Blt16BPPBufferShadowRect(pBuffer, uiPitch, &area))
|
|
{
|
|
// Blit has failed if false returned
|
|
return( FALSE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Now we have the video object and surface, call the shadow function
|
|
if(!Blt16BPPBufferShadowRectAlternateTable(pBuffer, uiPitch, &area))
|
|
{
|
|
// Blit has failed if false returned
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
// Mark as dirty if it's the backbuffer
|
|
//if ( uiDestVSurface == BACKBUFFER )
|
|
//{
|
|
// InvalidateBackbuffer( );
|
|
//}
|
|
|
|
UnLockVideoSurface( uiDestVSurface );
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN ShadowVideoSurfaceRect( UINT32 uiDestVSurface, INT32 X1, INT32 Y1, INT32 X2, INT32 Y2)
|
|
{
|
|
return( InternalShadowVideoSurfaceRect( uiDestVSurface, X1, Y1, X2, Y2, FALSE ) );
|
|
}
|
|
|
|
|
|
BOOLEAN ShadowVideoSurfaceRectUsingLowPercentTable( UINT32 uiDestVSurface, INT32 X1, INT32 Y1, INT32 X2, INT32 Y2)
|
|
{
|
|
return( InternalShadowVideoSurfaceRect( uiDestVSurface, X1, Y1, X2, Y2, TRUE ) );
|
|
}
|
|
|
|
|
|
//
|
|
// BltVSurfaceUsingDDBlt will always use Direct Draw Blt,NOT BltFast
|
|
BOOLEAN BltVSurfaceUsingDDBlt( HVSURFACE hDestVSurface, HVSURFACE hSrcVSurface, UINT32 fBltFlags, INT32 iDestX, INT32 iDestY, RECT *SrcRect, RECT *DestRect )
|
|
{
|
|
UINT32 uiDDFlags;
|
|
|
|
// Default flags
|
|
uiDDFlags = DDBLT_WAIT;
|
|
|
|
// Convert flags into DD flags, ( for transparency use, etc )
|
|
if ( fBltFlags & VS_BLT_USECOLORKEY )
|
|
{
|
|
uiDDFlags |= DDBLT_KEYSRC;
|
|
}
|
|
|
|
DDBltSurface( (LPDIRECTDRAWSURFACE2)hDestVSurface->pSurfaceData, DestRect, (LPDIRECTDRAWSURFACE2)hSrcVSurface->pSurfaceData,
|
|
SrcRect, uiDDFlags, NULL );
|
|
|
|
// Update backup surface with new data
|
|
if ( hDestVSurface->fFlags & VSURFACE_VIDEO_MEM_USAGE && !(hDestVSurface->fFlags & VSURFACE_RESERVED_SURFACE) )
|
|
{
|
|
UpdateBackupSurface( hDestVSurface );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
//
|
|
// This function will stretch the source image to the size of the dest rect.
|
|
//
|
|
// If the 2 images are not 16 Bpp, it returns false.
|
|
//
|
|
BOOLEAN BltStretchVideoSurface(UINT32 uiDestVSurface, UINT32 uiSrcVSurface, INT32 iDestX, INT32 iDestY, UINT32 fBltFlags, SGPRect *SrcRect, SGPRect *DestRect )
|
|
{
|
|
HVSURFACE hDestVSurface;
|
|
HVSURFACE hSrcVSurface;
|
|
|
|
#ifdef _DEBUG
|
|
gubVSDebugCode = DEBUGSTR_BLTSTRETCHVIDEOSURFACE_DST;
|
|
#endif
|
|
if( !GetVideoSurface( &hDestVSurface, uiDestVSurface ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
#ifdef _DEBUG
|
|
gubVSDebugCode = DEBUGSTR_BLTSTRETCHVIDEOSURFACE_SRC;
|
|
#endif
|
|
if( !GetVideoSurface( &hSrcVSurface, uiSrcVSurface ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//if the 2 images are not both 16bpp, return FALSE
|
|
if( (hDestVSurface->ubBitDepth != 16) && (hSrcVSurface->ubBitDepth != 16) )
|
|
return(FALSE);
|
|
|
|
if(!BltVSurfaceUsingDDBlt( hDestVSurface, hSrcVSurface, fBltFlags, iDestX, iDestY, (RECT*)SrcRect, (RECT*)DestRect ) )
|
|
{
|
|
//
|
|
// VO Blitter will set debug messages for error conditions
|
|
//
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN ShadowVideoSurfaceImage( UINT32 uiDestVSurface, HVOBJECT hImageHandle, INT32 iPosX, INT32 iPosY)
|
|
{
|
|
//Horizontal shadow
|
|
ShadowVideoSurfaceRect( uiDestVSurface, iPosX+3, iPosY+hImageHandle->pETRLEObject->usHeight, iPosX+hImageHandle->pETRLEObject->usWidth, iPosY+ hImageHandle->pETRLEObject->usHeight+3);
|
|
|
|
//vertical shadow
|
|
ShadowVideoSurfaceRect( uiDestVSurface, iPosX+hImageHandle->pETRLEObject->usWidth, iPosY+3, iPosX+hImageHandle->pETRLEObject->usWidth+3, iPosY+ hImageHandle->pETRLEObject->usHeight);
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN MakeVSurfaceFromVObject(UINT32 uiVObject, UINT16 usSubIndex, UINT32 *puiVSurface)
|
|
{
|
|
HVOBJECT hSrcVObject;
|
|
UINT32 uiVSurface;
|
|
VSURFACE_DESC hDesc;
|
|
|
|
if(GetVideoObject(&hSrcVObject, uiVObject))
|
|
{
|
|
// ATE: Memset
|
|
memset( &hDesc, 0, sizeof( VSURFACE_DESC ) );
|
|
hDesc.fCreateFlags=VSURFACE_CREATE_DEFAULT;
|
|
hDesc.usWidth=hSrcVObject->pETRLEObject[ usSubIndex ].usWidth;
|
|
hDesc.usHeight=hSrcVObject->pETRLEObject[ usSubIndex ].usHeight;
|
|
hDesc.ubBitDepth=PIXEL_DEPTH;
|
|
|
|
if(AddVideoSurface(&hDesc, &uiVSurface))
|
|
{
|
|
if(BltVideoObjectFromIndex(uiVSurface, uiVObject, usSubIndex, 0, 0, VO_BLT_SRCTRANSPARENCY, NULL))
|
|
{
|
|
*puiVSurface=uiVSurface;
|
|
return(TRUE);
|
|
}
|
|
else
|
|
DeleteVideoSurfaceFromIndex(uiVSurface);
|
|
}
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
void CheckValidVSurfaceIndex( UINT32 uiIndex )
|
|
{
|
|
BOOLEAN fAssertError = FALSE;
|
|
if( uiIndex == 0xffffffff )
|
|
{ //-1 index -- deleted
|
|
fAssertError = TRUE;
|
|
}
|
|
else if( uiIndex % 2 && uiIndex < 0xfffffff0 )
|
|
{ //odd numbers are reserved for vobjects
|
|
fAssertError = TRUE;
|
|
}
|
|
|
|
if( fAssertError )
|
|
{
|
|
CHAR8 str[60];
|
|
switch( gubVSDebugCode )
|
|
{
|
|
case DEBUGSTR_SETVIDEOSURFACETRANSPARENCY:
|
|
sprintf( str, "SetVideoSurfaceTransparency" );
|
|
break;
|
|
case DEBUGSTR_ADDVIDEOSURFACEREGION:
|
|
sprintf( str, "AddVideoSurfaceRegion" );
|
|
break;
|
|
case DEBUGSTR_GETVIDEOSURFACEDESCRIPTION:
|
|
sprintf( str, "GetVideoSurfaceDescription" );
|
|
break;
|
|
case DEBUGSTR_BLTVIDEOSURFACE_DST:
|
|
sprintf( str, "BltVideoSurface (dest)" );
|
|
break;
|
|
case DEBUGSTR_BLTVIDEOSURFACE_SRC:
|
|
sprintf( str, "BltVideoSurface (src)" );
|
|
break;
|
|
case DEBUGSTR_COLORFILLVIDEOSURFACEAREA:
|
|
sprintf( str, "ColorFillVideoSurfaceArea" );
|
|
break;
|
|
case DEBUGSTR_SHADOWVIDEOSURFACERECT:
|
|
sprintf( str, "ShadowVideoSurfaceRect" );
|
|
break;
|
|
case DEBUGSTR_BLTSTRETCHVIDEOSURFACE_DST:
|
|
sprintf( str, "BltStretchVideoSurface (dest)" );
|
|
break;
|
|
case DEBUGSTR_BLTSTRETCHVIDEOSURFACE_SRC:
|
|
sprintf( str, "BltStretchVideoSurface (src)" );
|
|
break;
|
|
case DEBUGSTR_DELETEVIDEOSURFACEFROMINDEX:
|
|
sprintf( str, "DeleteVideoSurfaceFromIndex" );
|
|
break;
|
|
case DEBUGSTR_NONE:
|
|
default:
|
|
sprintf( str, "GetVideoSurface" );
|
|
break;
|
|
}
|
|
if( uiIndex == 0xffffffff )
|
|
{
|
|
AssertMsg( 0, String( "Trying to %s with deleted index -1." , str ) );
|
|
}
|
|
else
|
|
{
|
|
AssertMsg( 0, String( "Trying to %s using a VOBJECT ID %d!", str, uiIndex ) );
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef SGP_VIDEO_DEBUGGING
|
|
typedef struct DUMPFILENAME
|
|
{
|
|
CHAR8 str[256];
|
|
}DUMPFILENAME;
|
|
void DumpVSurfaceInfoIntoFile( const STR8 filename, BOOLEAN fAppend )
|
|
{
|
|
VSURFACE_NODE *curr;
|
|
FILE *fp;
|
|
DUMPFILENAME *pName, *pCode;
|
|
UINT32 *puiCounter;
|
|
CHAR8 tempName[ 256 ];
|
|
CHAR8 tempCode[ 256 ];
|
|
UINT32 i, uiUniqueID;
|
|
BOOLEAN fFound;
|
|
if( !guiVSurfaceSize )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( fAppend )
|
|
{
|
|
fp = fopen( filename, "a" );
|
|
}
|
|
else
|
|
{
|
|
fp = fopen( filename, "w" );
|
|
}
|
|
Assert( fp );
|
|
|
|
//Allocate enough strings and counters for each node.
|
|
pName = (DUMPFILENAME*)MemAlloc( sizeof( DUMPFILENAME ) * guiVSurfaceSize );
|
|
pCode = (DUMPFILENAME*)MemAlloc( sizeof( DUMPFILENAME ) * guiVSurfaceSize );
|
|
memset( pName, 0, sizeof( DUMPFILENAME ) * guiVSurfaceSize );
|
|
memset( pCode, 0, sizeof( DUMPFILENAME ) * guiVSurfaceSize );
|
|
puiCounter = (UINT32*)MemAlloc( 4 * guiVSurfaceSize );
|
|
memset( puiCounter, 0, 4 * guiVSurfaceSize );
|
|
|
|
//Loop through the list and record every unique filename and count them
|
|
uiUniqueID = 0;
|
|
curr = gpVSurfaceHead;
|
|
while( curr )
|
|
{
|
|
strcpy( tempName, curr->pName );
|
|
strcpy( tempCode, curr->pCode );
|
|
fFound = FALSE;
|
|
for( i = 0; i < uiUniqueID; i++ )
|
|
{
|
|
if( !_stricmp( tempName, pName[i].str ) && !_stricmp( tempCode, pCode[i].str ) )
|
|
{ //same string
|
|
fFound = TRUE;
|
|
(puiCounter[ i ])++;
|
|
break;
|
|
}
|
|
}
|
|
if( !fFound )
|
|
{
|
|
strcpy( pName[i].str, tempName );
|
|
strcpy( pCode[i].str, tempCode );
|
|
(puiCounter[ i ])++;
|
|
uiUniqueID++;
|
|
}
|
|
curr = curr->next;
|
|
}
|
|
|
|
//Now dump the info.
|
|
fprintf( fp, "-----------------------------------------------\n" );
|
|
fprintf( fp, "%d unique vSurface names exist in %d VSurfaces\n", uiUniqueID, guiVSurfaceSize );
|
|
fprintf( fp, "-----------------------------------------------\n\n" );
|
|
for( i = 0; i < uiUniqueID; i++ )
|
|
{
|
|
fprintf( fp, "%d occurrences of %s\n", puiCounter[i], pName[i].str );
|
|
fprintf( fp, "%s\n\n", pCode[i].str );
|
|
}
|
|
fprintf( fp, "\n-----------------------------------------------\n\n" );
|
|
|
|
//Free all memory associated with this operation.
|
|
MemFree( pName );
|
|
MemFree( pCode );
|
|
MemFree( puiCounter );
|
|
fclose( fp );
|
|
}
|
|
|
|
//Debug wrapper for adding vsurfaces
|
|
BOOLEAN _AddAndRecordVSurface( VSURFACE_DESC *VSurfaceDesc, UINT32 *uiIndex, UINT32 uiLineNum, const STR8 pSourceFile )
|
|
{
|
|
UINT16 usLength;
|
|
CHAR8 str[256];
|
|
if( !AddStandardVideoSurface( VSurfaceDesc, uiIndex ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//record the filename of the vsurface (some are created via memory though)
|
|
usLength = strlen( VSurfaceDesc->ImageFile ) + 1;
|
|
gpVSurfaceTail->pName = (STR8)MemAlloc( usLength );
|
|
memset( gpVSurfaceTail->pName, 0, usLength );
|
|
strcpy( gpVSurfaceTail->pName, VSurfaceDesc->ImageFile );
|
|
|
|
//record the code location of the calling creating function.
|
|
sprintf( str, "%s -- line(%d)", pSourceFile, uiLineNum );
|
|
usLength = strlen( str ) + 1;
|
|
gpVSurfaceTail->pCode = (STR8)MemAlloc( usLength );
|
|
memset( gpVSurfaceTail->pCode, 0, usLength );
|
|
strcpy( gpVSurfaceTail->pCode, str );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#endif
|
|
|