Files
source/sgp/himage.cpp
majcostaandGitHub 381ab936eb Rename 'Standard Gaming Platform' to 'sgp' (#246)
* rename 'Standard Gaming Platform' to 'sgp'

* Adapt CMakeLists.txt files to renamed SGP directory

* Lowercase it
2023-10-23 10:18:20 -03:00

1091 lines
30 KiB
C++

#include "builddefines.h"
#include <math.h>
#include <stdlib.h>
#include "types.h"
#include "string.h"
#include "debug.h"
#include "fileman.h"
#include "himage.h"
#include "impTGA.h"
#include "pcx.h"
#include "STCI.h"
#include "PngLoader.h"
#include "wcheck.h"
#include "Compression.h"
#include "vobject.h"
#include "vobject_blitters.h"
#include <vfs/Core/vfs.h>
const vfs::String::str_t CONST_DOTJPC(L".jpc.7z");
// This is the color substituted to keep a 24bpp->16bpp color
// from going transparent (0x0000) -- DB
#define BLACK_SUBSTITUTE 0x0001
UINT16 gusAlphaMask = 0;
UINT16 gusRedMask = 0;
UINT16 gusGreenMask = 0;
UINT16 gusBlueMask = 0;
INT16 gusRedShift = 0;
INT16 gusBlueShift = 0;
INT16 gusGreenShift = 0;
// this funky union is used for fast 16-bit pixel format conversions
typedef union
{
struct
{
UINT16 usLower;
UINT16 usHigher;
};
UINT32 uiValue;
} SplitUINT32;
namespace ImageFileType
{
typedef std::map<vfs::String, int, vfs::String::Less> ExtMap_t;
static int map(vfs::String const& ext)
{
static ExtMap_t _ext_map;
static bool inited = false;
if(!inited)
{
_ext_map["pcx"] = PCX_FILE_READER;
_ext_map["tga"] = TGA_FILE_READER;
_ext_map["sti"] = STCI_FILE_READER;
_ext_map["png"] = PNG_FILE_READER;
_ext_map["jpc.7z"] = JPC_FILE_READER;
inited = true;
}
ExtMap_t::const_iterator cit = _ext_map.find(ext);
if(cit != _ext_map.end())
{
return cit->second;
}
return UNKNOWN_FILE_READER;
}
static int getFileReaderType(std::string& filename, TestOrder order)
{
std::string::size_type pos = filename.find_last_of(".");
std::string ext = filename.substr(pos+1, std::string::npos);
if(ext.empty())
{
ext = "pcx";
filename += ".pcx";
}
int reader_type = map(ext);
/*
* if DEFAULT, then just check existance of file
* if not STI, then there is no different load order, just continue as usual
*/
if(order == DEFAULT || reader_type != STCI_FILE_READER)
{
return getVFS()->fileExists(filename) ? reader_type : UNKNOWN_FILE_READER;
}
/*
* file must have originally been an STI file, but should be treated as a JPC or a PNG file
*/
else if(order == JPC || order == PNG)
{
vfs::String file = filename.substr(0, pos+1).append(order == JPC ? "jpc.7z" : "png");
if( getVFS()->fileExists(file) )
{
filename = file.utf8();
return order == JPC ? JPC_FILE_READER : PNG_FILE_READER;
}
return UNKNOWN_FILE_READER;
}
/*
* file must have originally been an STI file, but should be treated as a JPC or a PNG file
* if the replacement filetypes don't exist, fall back to STI
*/
else if(order == JPC_FALLBACK || order == PNG_FALLBACK)
{
vfs::String file = filename.substr(0, pos+1).append(order == JPC_FALLBACK ? "jpc.7z" : "png");
if( getVFS()->fileExists(file) )
{
filename = file.utf8();
return order == JPC_FALLBACK ? JPC_FILE_READER : PNG_FILE_READER;
}
// fallback to original type
return getVFS()->fileExists(filename) ? reader_type : UNKNOWN_FILE_READER;
}
return UNKNOWN_FILE_READER;
}
};
HIMAGE CreateImage( SGPFILENAME ImageFile, UINT16 fContents, ImageFileType::TestOrder order )
{
HIMAGE hImage = NULL;
CHAR8 ExtensionSep[] = ".";
UINT32 iFileLoader;
std::string filename(ImageFile);
iFileLoader = ImageFileType::getFileReaderType(filename, order);
if ( iFileLoader == UNKNOWN_FILE_READER )
{
//If in debug, make fatal!
#ifdef _DEBUG
//FatalError( "Resource file %s does not exist.", ImageFile );
#endif
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_2, String("Resource file %s does not exist.", ImageFile) );
return( NULL );
}
// Create memory for image structure
hImage = (HIMAGE)MemAlloc( sizeof( image_type ) );
AssertMsg( hImage, "Failed to allocate memory for hImage in CreateImage");
// Initialize some values
memset( hImage, 0, sizeof( image_type ) );
//hImage->fFlags = 0;
// Set data pointers to NULL
//hImage->pImageData = NULL;
//hImage->pPalette = NULL;
//hImage->pui16BPPPalette = NULL;
// Set filename and loader
strncpy( hImage->ImageFile, /*ImageFile*/filename.c_str(), filename.length() );
hImage->iFileLoader = iFileLoader;
if ( !LoadImageData( hImage, fContents ) )
{
return( NULL );
}
// All is fine, image is loaded and allocated, return pointer
return( hImage );
}
BOOLEAN DestroyImage( HIMAGE hImage )
{
Assert( hImage != NULL );
// First delete contents
ReleaseImageData( hImage, IMAGE_ALLDATA );//hImage->fFlags );
// Now free structure
MemFree( hImage );
return( TRUE );
}
BOOLEAN ReleaseImageData( HIMAGE hImage, UINT16 fContents )
{
Assert( hImage != NULL );
if ( (fContents & IMAGE_PALETTE) && (hImage->fFlags & IMAGE_PALETTE) )
{
//Destroy palette
if( hImage->pPalette != NULL )
{
MemFree( hImage->pPalette );
hImage->pPalette = NULL;
}
if ( hImage->pui16BPPPalette != NULL )
{
MemFree( hImage->pui16BPPPalette );
hImage->pui16BPPPalette = NULL;
}
// Remove contents flag
hImage->fFlags = hImage->fFlags ^ IMAGE_PALETTE;
}
if ( (fContents & IMAGE_BITMAPDATA) && (hImage->fFlags & IMAGE_BITMAPDATA) )
{
//Destroy image data
Assert( hImage->pImageData != NULL );
MemFree( hImage->pImageData );
hImage->pImageData = NULL;
if (hImage->usNumberOfObjects > 0)
{
MemFree( hImage->pETRLEObject );
}
// Remove contents flag
hImage->fFlags = hImage->fFlags ^ IMAGE_BITMAPDATA;
}
if ( (fContents & IMAGE_APPDATA) && (hImage->fFlags & IMAGE_APPDATA) )
{
// get rid of the APP DATA
if ( hImage->pAppData != NULL )
{
MemFree( hImage->pAppData );
hImage->fFlags &= (~IMAGE_APPDATA);
}
}
return( TRUE );
}
BOOLEAN LoadImageData( HIMAGE hImage, UINT16 fContents )
{
BOOLEAN fReturnVal = FALSE;
Assert( hImage != NULL );
// Switch on file loader
switch( hImage->iFileLoader )
{
case TGA_FILE_READER:
fReturnVal = LoadTGAFileToImage( hImage, fContents );
break;
case PCX_FILE_READER:
fReturnVal = LoadPCXFileToImage( hImage, fContents );
break;
case STCI_FILE_READER:
fReturnVal = LoadSTCIFileToImage( hImage, fContents );
break;
case PNG_FILE_READER:
fReturnVal = LoadPNGFileToImage( hImage, fContents );
break;
case JPC_FILE_READER:
fReturnVal = LoadJPCFileToImage( hImage, fContents );
break;
default:
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_2, "Unknown image loader was specified." );
}
if ( !fReturnVal )
{
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_2, "Error occured while reading image data." );
}
return( fReturnVal );
}
BOOLEAN CopyImageToBuffer( HIMAGE hImage, UINT32 fBufferType, BYTE *pDestBuf, UINT16 usDestWidth, UINT16 usDestHeight, UINT16 usX, UINT16 usY, SGPRect *srcRect )
{
// Use blitter based on type of image
Assert( hImage != NULL );
if ( hImage->ubBitDepth == 8 && fBufferType == BUFFER_8BPP )
{
#ifndef NO_ZLIB_COMPRESSION
if ( hImage->fFlags & IMAGE_COMPRESSED )
{
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_2, "Copying Compressed 8 BPP Imagery." );
return( Copy8BPPCompressedImageTo8BPPBuffer( hImage, pDestBuf, usDestWidth, usDestHeight, usX, usY, srcRect ) );
}
#endif
// Default do here
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_2, "Copying 8 BPP Imagery." );
return ( Copy8BPPImageTo8BPPBuffer( hImage, pDestBuf, usDestWidth, usDestHeight, usX, usY, srcRect ) );
}
if ( hImage->ubBitDepth == 8 && fBufferType == BUFFER_16BPP )
{
#ifndef NO_ZLIB_COMPRESSION
if ( hImage->fFlags & IMAGE_COMPRESSED )
{
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Copying Compressed 8 BPP Imagery to 16BPP Buffer." );
return ( Copy8BPPCompressedImageTo16BPPBuffer( hImage, pDestBuf, usDestWidth, usDestHeight, usX, usY, srcRect ) );
}
#endif
// Default do here
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Copying 8 BPP Imagery to 16BPP Buffer." );
return ( Copy8BPPImageTo16BPPBuffer( hImage, pDestBuf, usDestWidth, usDestHeight, usX, usY, srcRect ) );
}
if ( hImage->ubBitDepth == 16 && fBufferType == BUFFER_16BPP )
{
#ifndef NO_ZLIB_COMPRESSION
if ( hImage->fFlags & IMAGE_COMPRESSED )
{
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Automatically Copying Compressed 16 BPP Imagery." );
return( Copy16BPPCompressedImageTo16BPPBuffer( hImage, pDestBuf, usDestWidth, usDestHeight, usX, usY, srcRect ) );
}
#endif
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Automatically Copying 16 BPP Imagery." );
return( Copy16BPPImageTo16BPPBuffer( hImage, pDestBuf, usDestWidth, usDestHeight, usX, usY, srcRect ) );
}
if ( hImage->ubBitDepth == 24 && fBufferType == BUFFER_16BPP )
{
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Copying 24 BPP Imagery to 16BPP Buffer." );
AssertMsg(false,"not yet implemented");
return( FALSE );
}
if ( hImage->ubBitDepth == 32 && fBufferType == BUFFER_16BPP )
{
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Copying 32 BPP Imagery to 16BPP Buffer." );
return Blt32BPPTo16BPPTrans((UINT16*)pDestBuf, usDestWidth * sizeof(UINT16), hImage->p32BPPData, usDestWidth*sizeof(UINT32), 0,0,0,0,usDestWidth, usDestHeight);
}
return( FALSE );
}
#ifndef NO_ZLIB_COMPRESSION
BOOLEAN Copy8BPPCompressedImageTo8BPPBuffer( HIMAGE hImage, BYTE *pDestBuf, UINT16 usDestWidth, UINT16 usDestHeight, UINT16 usX, UINT16 usY, SGPRect *srcRect )
{
UINT32 uiNumLines;
UINT32 uiLineSize;
UINT32 uiCnt;
UINT8 * pDest;
UINT32 uiDestStart;
UINT8 * pScanLine;
PTR pDecompPtr;
UINT32 uiDecompressed;
// Assertions
Assert( hImage != NULL );
Assert( hImage->pCompressedImageData != NULL );
// Validations
CHECKF( usX >= 0 );
CHECKF( usX < usDestWidth );
CHECKF( usY >= 0 );
CHECKF( usY < usDestHeight );
CHECKF( srcRect->iRight > srcRect->iLeft );
CHECKF( srcRect->iBottom > srcRect->iTop );
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "8BPP to 8BPP Compressed Blitter Called!" );
// determine where to start Copying and rectangle size
uiDestStart = usY * usDestWidth + usX;
uiNumLines = srcRect->iBottom - srcRect->iTop;
uiLineSize = srcRect->iRight - srcRect->iLeft;
Assert( usDestWidth >= uiLineSize );
Assert( usDestHeight >= uiNumLines );
pDest = (UINT8 *) pDestBuf + uiDestStart;
// Copying a portion of a compressed image is rather messy
// because we have to decompress past all the data we want
// to skip.
// To keep memory requirements small and regular, we will
// decompress one scanline at a time even if none of the data will
// be blitted (but stop when the bottom line of the rectangle
// to blit has been done).
// initialize the decompression routines
pDecompPtr = DecompressInit( hImage->pCompressedImageData, hImage->usWidth * hImage->usHeight );
CHECKF( pDecompPtr );
// Allocate memory for one scanline
pScanLine = (UINT8*) MemAlloc( hImage->usWidth );
CHECKF( pScanLine );
memset( pScanLine, 0, hImage->usWidth );
// go past all the scanlines we don't need to process
for (uiCnt = 0; uiCnt < (UINT32) srcRect->iTop; uiCnt++)
{
uiDecompressed = Decompress( pDecompPtr, pScanLine, hImage->usWidth );
Assert( uiDecompressed == hImage->usWidth );
}
// now we start Copying
for (uiCnt = 0; uiCnt < uiNumLines - 1; uiCnt++)
{
// decompress a scanline
uiDecompressed = Decompress( pDecompPtr, pScanLine, hImage->usWidth );
Assert( uiDecompressed == hImage->usWidth );
// and blit
// memcpy( pDest, pScanLine + srcRect->iLeft, uiLineSize );
pDest += usDestWidth;
}
// decompress the last scanline and blit
uiDecompressed = Decompress( pDecompPtr, pScanLine, hImage->usWidth );
Assert( uiDecompressed == hImage->usWidth );
// memcpy( pDest, pScanLine + srcRect->iLeft, uiLineSize );
DecompressFini( pDecompPtr );
return( TRUE );
}
BOOLEAN Copy8BPPCompressedImageTo16BPPBuffer( HIMAGE hImage, BYTE *pDestBuf, UINT16 usDestWidth, UINT16 usDestHeight, UINT16 usX, UINT16 usY, SGPRect *srcRect )
{
UINT32 uiNumLines;
UINT32 uiLineSize;
UINT32 uiLine;
UINT32 uiCol;
UINT16 * pDest;
UINT16 * pDestTemp;
UINT32 uiDestStart;
UINT8 * pScanLine;
UINT8 * pScanLineTemp;
PTR pDecompPtr;
UINT32 uiDecompressed;
UINT16 * p16BPPPalette;
// Assertions
Assert( hImage != NULL );
Assert( hImage->pCompressedImageData != NULL );
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Start check" );
// Validations
CHECKF( usX >= 0 );
CHECKF( usX < usDestWidth );
CHECKF( usY >= 0 );
CHECKF( usY < usDestHeight );
CHECKF( srcRect->iRight > srcRect->iLeft );
CHECKF( srcRect->iBottom > srcRect->iTop );
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "End check" );
p16BPPPalette = hImage->pui16BPPPalette;
// determine where to start Copying and rectangle size
uiDestStart = usY * usDestWidth + usX;
uiNumLines = srcRect->iBottom - srcRect->iTop;
uiLineSize = srcRect->iRight - srcRect->iLeft;
Assert( usDestWidth >= uiLineSize );
Assert( usDestHeight >= uiNumLines );
pDest = (UINT16 *) pDestBuf;
pDest += uiDestStart;
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, String( "Start Copying at %p", pDest ) );
// Copying a portion of a compressed image is rather messy
// because we have to decompress past all the data we want
// to skip.
// To keep memory requirements small and regular, we will
// decompress one scanline at a time even if none of the data will
// be blitted (but stop when the bottom line of the rectangle
// to blit has been done).
// initialize the decompression routines
pDecompPtr = DecompressInit( hImage->pCompressedImageData, hImage->usWidth * hImage->usHeight );
CHECKF( pDecompPtr );
// Allocate memory for one scanline
pScanLine = (UINT8*) MemAlloc( hImage->usWidth );
CHECKF( pScanLine );
memset( pScanLine, 0, hImage->usWidth );
// go past all the scanlines we don't need to process
for (uiLine = 0; uiLine < (UINT32) srcRect->iTop; uiLine++)
{
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Skipping scanline" );
uiDecompressed = Decompress( pDecompPtr, pScanLine, hImage->usWidth );
Assert( uiDecompressed == hImage->usWidth );
}
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Actually Copying" );
// now we start Copying
for (uiLine = 0; uiLine < uiNumLines - 1; uiLine++)
{
// decompress a scanline
uiDecompressed = Decompress( pDecompPtr, pScanLine, hImage->usWidth );
Assert( uiDecompressed == hImage->usWidth );
// set pointers and blit
pDestTemp = pDest;
pScanLineTemp = pScanLine + srcRect->iLeft;
for (uiCol = 0; uiCol < uiLineSize; uiCol++ )
{
*pDestTemp = p16BPPPalette[ *pScanLineTemp ];
pDestTemp++;
pScanLineTemp++;
}
pDest += usDestWidth;
}
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, String( "End Copying at %p", pDest ) );
DecompressFini( pDecompPtr );
return( TRUE );
}
BOOLEAN Copy16BPPCompressedImageTo16BPPBuffer( HIMAGE hImage, BYTE *pDestBuf, UINT16 usDestWidth, UINT16 usDestHeight, UINT16 usX, UINT16 usY, SGPRect *srcRect )
{
// 16BPP Compressed image has not been implemented yet
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_2, "16BPP Compressed imagery blitter has not been implemented yet." );
return( FALSE );
}
#endif //NO_ZLIB_COMPRESSION
BOOLEAN Copy8BPPImageTo8BPPBuffer( HIMAGE hImage, BYTE *pDestBuf, UINT16 usDestWidth, UINT16 usDestHeight, UINT16 usX, UINT16 usY, SGPRect *srcRect )
{
UINT32 uiSrcStart, uiDestStart, uiNumLines, uiLineSize;
UINT32 cnt;
UINT8 *pDest, *pSrc;
// Assertions
Assert( hImage != NULL );
Assert( hImage->p16BPPData != NULL );
// Validations
CHECKF( usX >= 0 );
CHECKF( usX < usDestWidth );
CHECKF( usY >= 0 );
CHECKF( usY < usDestHeight );
CHECKF( srcRect->iRight > srcRect->iLeft );
CHECKF( srcRect->iBottom > srcRect->iTop );
// Determine memcopy coordinates
uiSrcStart = srcRect->iTop * hImage->usWidth + srcRect->iLeft;
uiDestStart = usY * usDestWidth + usX;
uiNumLines = ( srcRect->iBottom - srcRect->iTop ) + 1;
uiLineSize = ( srcRect->iRight - srcRect->iLeft ) + 1;
Assert( usDestWidth >= uiLineSize );
Assert( usDestHeight >= uiNumLines );
// Copy line by line
pDest = ( UINT8*)pDestBuf + uiDestStart;
pSrc = hImage->p8BPPData + uiSrcStart;
for( cnt = 0; cnt < uiNumLines-1; cnt++ )
{
memcpy( pDest, pSrc, uiLineSize );
pDest += usDestWidth;
pSrc += hImage->usWidth;
}
// Do last line
memcpy( pDest, pSrc, uiLineSize );
return( TRUE );
}
BOOLEAN Copy16BPPImageTo16BPPBuffer( HIMAGE hImage, BYTE *pDestBuf, UINT16 usDestWidth, UINT16 usDestHeight, UINT16 usX, UINT16 usY, SGPRect *srcRect )
{
UINT32 uiSrcStart, uiDestStart, uiNumLines, uiLineSize;
UINT32 cnt;
UINT16 *pDest, *pSrc;
Assert( hImage != NULL );
Assert( hImage->p16BPPData != NULL );
// Validations
CHECKF( usX >= 0 );
CHECKF( usX < hImage->usWidth );
CHECKF( usY >= 0 );
CHECKF( usY < hImage->usHeight );
CHECKF( srcRect->iRight > srcRect->iLeft );
CHECKF( srcRect->iBottom > srcRect->iTop );
// Determine memcopy coordinates
uiSrcStart = srcRect->iTop * hImage->usWidth + srcRect->iLeft;
uiDestStart = usY * usDestWidth + usX;
uiNumLines = ( srcRect->iBottom - srcRect->iTop ) + 1;
uiLineSize = ( srcRect->iRight - srcRect->iLeft ) + 1;
CHECKF( usDestWidth >= uiLineSize );
CHECKF( usDestHeight >= uiNumLines );
// Copy line by line
pDest = ( UINT16*)pDestBuf + uiDestStart;
pSrc = hImage->p16BPPData + uiSrcStart;
for( cnt = 0; cnt < uiNumLines-1; cnt++ )
{
memcpy( pDest, pSrc, uiLineSize * 2 );
pDest += usDestWidth;
pSrc += hImage->usWidth;
}
// Do last line
memcpy( pDest, pSrc, uiLineSize * 2 );
return( TRUE );
}
BOOLEAN Extract8BPPCompressedImageToBuffer( HIMAGE hImage, BYTE *pDestBuf )
{
return( FALSE );
}
BOOLEAN Extract16BPPCompressedImageToBuffer( HIMAGE hImage, BYTE *pDestBuf )
{
return( FALSE );
}
BOOLEAN Copy8BPPImageTo16BPPBuffer( HIMAGE hImage, BYTE *pDestBuf, UINT16 usDestWidth, UINT16 usDestHeight, UINT16 usX, UINT16 usY, SGPRect *srcRect )
{
UINT32 uiSrcStart, uiDestStart, uiNumLines, uiLineSize;
UINT32 rows, cols;
UINT8 *pSrc, *pSrcTemp;
UINT16 *pDest, *pDestTemp;
UINT16 *p16BPPPalette;
p16BPPPalette = hImage->pui16BPPPalette;
// Assertions
Assert( p16BPPPalette != NULL );
Assert( hImage != NULL );
// Validations
CHECKF( hImage->p16BPPData != NULL );
CHECKF( usX >= 0 );
CHECKF( usX < usDestWidth );
CHECKF( usY >= 0 );
CHECKF( usY < usDestHeight );
CHECKF( srcRect->iRight > srcRect->iLeft );
CHECKF( srcRect->iBottom > srcRect->iTop );
// Determine memcopy coordinates
uiSrcStart = srcRect->iTop * hImage->usWidth + srcRect->iLeft;
uiDestStart = usY * usDestWidth + usX;
uiNumLines = ( srcRect->iBottom - srcRect->iTop );
uiLineSize = ( srcRect->iRight - srcRect->iLeft );
CHECKF( usDestWidth >= uiLineSize );
CHECKF( usDestHeight >= uiNumLines );
// Convert to Pixel specification
pDest = ( UINT16*)pDestBuf + uiDestStart;
pSrc = hImage->p8BPPData + uiSrcStart;
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, String( "Start Copying at %p", pDest ) );
// For every entry, look up into 16BPP palette
for( rows = 0; rows < uiNumLines-1; rows++ )
{
pDestTemp = pDest;
pSrcTemp = pSrc;
for ( cols = 0; cols < uiLineSize; cols++ )
{
*pDestTemp = p16BPPPalette[ *pSrcTemp ];
pDestTemp++;
pSrcTemp++;
}
pDest += usDestWidth;
pSrc += hImage->usWidth;
}
// Do last line
DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, String( "End Copying at %p", pDest ) );
return( TRUE );
}
UINT16 *Create16BPPPalette( SGPPaletteEntry *pPalette )
{
UINT16 *p16BPPPalette, r16, g16, b16, usColor;
UINT32 cnt;
UINT8 r,g,b;
Assert( pPalette != NULL );
p16BPPPalette = (UINT16 *) MemAlloc( sizeof( UINT16 ) * 256 );
memset( p16BPPPalette, 0, sizeof( UINT16 ) * 256 );
for ( cnt = 0; cnt < 256; cnt++ )
{
r = pPalette[ cnt ].peRed;
g = pPalette[ cnt ].peGreen;
b = pPalette[ cnt ].peBlue;
if(gusRedShift < 0)
r16=((UINT16)r>>abs(gusRedShift));
else
r16=((UINT16)r<<gusRedShift);
if(gusGreenShift < 0)
g16=((UINT16)g>>abs(gusGreenShift));
else
g16=((UINT16)g<<gusGreenShift);
if(gusBlueShift < 0)
b16=((UINT16)b>>abs(gusBlueShift));
else
b16=((UINT16)b<<gusBlueShift);
usColor = (r16&gusRedMask)|(g16&gusGreenMask)|(b16&gusBlueMask);
if(usColor==0)
{
if((r+g+b)!=0)
usColor=BLACK_SUBSTITUTE | gusAlphaMask;
}
else
usColor |= gusAlphaMask;
p16BPPPalette[ cnt ] = usColor;
}
return( p16BPPPalette );
}
/**********************************************************************************************
Create16BPPPaletteShaded
Creates an 8 bit to 16 bit palette table, and modifies the colors as it builds.
Parameters:
rscale, gscale, bscale:
Color mode: Percentages (255=100%) of color to translate into destination palette.
Mono mode: Color for monochrome palette.
mono:
TRUE or FALSE to create a monochrome palette. In mono mode, Luminance values for
colors are calculated, and the RGB color is shaded according to each pixel's brightness.
This can be used in several ways:
1) To "brighten" a palette, pass down RGB values that are higher than 100% ( > 255) for all
three. mono=FALSE.
2) To "darken" a palette, do the same with less than 100% ( < 255) values. mono=FALSE.
3) To create a "glow" palette, select mono=TRUE, and pass the color in the RGB parameters.
4) For gamma correction, pass in weighted values for each color.
**********************************************************************************************/
UINT16 *Create16BPPPaletteShaded( SGPPaletteEntry *pPalette, UINT32 rscale, UINT32 gscale, UINT32 bscale, BOOLEAN mono)
{
UINT16 *p16BPPPalette, r16, g16, b16, usColor;
UINT32 cnt, lumin;
UINT32 rmod, gmod, bmod;
UINT8 r,g,b;
Assert( pPalette != NULL );
p16BPPPalette = (UINT16 *) MemAlloc( sizeof( UINT16 ) * 256 );
memset( p16BPPPalette, 0, sizeof( UINT16 ) * 256 );
for ( cnt = 0; cnt < 256; cnt++ )
{
if(mono)
{
lumin=(pPalette[ cnt ].peRed*299/1000)+ (pPalette[ cnt ].peGreen*587/1000)+(pPalette[ cnt ].peBlue*114/1000);
rmod=(rscale*lumin)/256;
gmod=(gscale*lumin)/256;
bmod=(bscale*lumin)/256;
}
else
{
rmod = (rscale*pPalette[ cnt ].peRed/256);
gmod = (gscale*pPalette[ cnt ].peGreen/256);
bmod = (bscale*pPalette[ cnt ].peBlue/256);
}
r = (UINT8)__min(rmod, 255);
g = (UINT8)__min(gmod, 255);
b = (UINT8)__min(bmod, 255);
if(gusRedShift < 0)
r16=((UINT16)r>>(-gusRedShift));
else
r16=((UINT16)r<<gusRedShift);
if(gusGreenShift < 0)
g16=((UINT16)g>>(-gusGreenShift));
else
g16=((UINT16)g<<gusGreenShift);
if(gusBlueShift < 0)
b16=((UINT16)b>>(-gusBlueShift));
else
b16=((UINT16)b<<gusBlueShift);
// Prevent creation of pure black color
usColor = (r16&gusRedMask)|(g16&gusGreenMask)|(b16&gusBlueMask);
if(usColor==0)
{
if((r+g+b)!=0)
usColor=BLACK_SUBSTITUTE | gusAlphaMask;
}
else
usColor |= gusAlphaMask;
p16BPPPalette[ cnt ] = usColor;
}
return( p16BPPPalette );
}
// Convert from RGB to 16 bit value
UINT16 Get16BPPColor( UINT32 RGBValue )
{
UINT16 r16, g16, b16, usColor = 0;
UINT8 r,g,b;
r = SGPGetRValue( RGBValue );
g = SGPGetGValue( RGBValue );
b = SGPGetBValue( RGBValue );
if(gusRedShift < 0)
r16=((UINT16)r>>abs(gusRedShift));
else
r16=((UINT16)r<<gusRedShift);
if(gusGreenShift < 0)
g16=((UINT16)g>>abs(gusGreenShift));
else
g16=((UINT16)g<<gusGreenShift);
if(gusBlueShift < 0)
b16=((UINT16)b>>abs(gusBlueShift));
else
b16=((UINT16)b<<gusBlueShift);
usColor=(r16&gusRedMask)|(g16&gusGreenMask)|(b16&gusBlueMask);
// if our color worked out to absolute black, and the original wasn't
// absolute black, convert it to a VERY dark grey to avoid transparency
// problems
if(usColor==0)
{
if(RGBValue!=0)
usColor=BLACK_SUBSTITUTE | gusAlphaMask;
}
else
usColor |= gusAlphaMask;
return(usColor);
}
// Convert from 16 BPP to RGBvalue
UINT32 GetRGBColor( UINT16 Value16BPP )
{
UINT16 r16, g16, b16;
UINT32 r,g,b,val;
r16 = Value16BPP & gusRedMask;
g16 = Value16BPP & gusGreenMask;
b16 = Value16BPP & gusBlueMask;
if(gusRedShift < 0)
r=((UINT32)r16<<abs(gusRedShift));
else
r=((UINT32)r16>>gusRedShift);
if(gusGreenShift < 0)
g=((UINT32)g16<<abs(gusGreenShift));
else
g=((UINT32)g16>>gusGreenShift);
if(gusBlueShift < 0)
b=((UINT32)b16<<abs(gusBlueShift));
else
b=((UINT32)b16>>gusBlueShift);
r &= 0x000000ff;
g &= 0x000000ff;
b &= 0x000000ff;
val = FROMRGB(r,g,b);
return(val);
}
//*****************************************************************************
//
// ConvertToPaletteEntry
//
// Parameter List : Converts from RGB to SGPPaletteEntry
//
// Return Value pointer to the SGPPaletteEntry
//
// Modification History :
// Dec 15th 1996->modified for use by Wizardry
//
//*****************************************************************************
SGPPaletteEntry *ConvertRGBToPaletteEntry(UINT8 sbStart, UINT8 sbEnd, UINT8 *pOldPalette)
{
UINT16 Index;
SGPPaletteEntry *pPalEntry;
SGPPaletteEntry *pInitEntry;
pPalEntry = (SGPPaletteEntry *)MemAlloc(sizeof(SGPPaletteEntry) * 256);
memset( pPalEntry, 0, sizeof(SGPPaletteEntry) * 256 );
pInitEntry = pPalEntry;
DbgMessage(TOPIC_HIMAGE, DBG_LEVEL_0, "Converting RGB palette to SGPPaletteEntry");
for(Index=0; Index <= (sbEnd-sbStart);Index++)
{
pPalEntry->peRed = *(pOldPalette + (Index*3));
pPalEntry->peGreen = *(pOldPalette + (Index*3) + 1);
pPalEntry->peBlue = *(pOldPalette + (Index*3) + 2);
pPalEntry->peFlags = 0;
pPalEntry++;
}
return pInitEntry;
}
BOOLEAN GetETRLEImageData( HIMAGE hImage, ETRLEData *pBuffer )
{
// Assertions
Assert( hImage != NULL );
Assert( pBuffer != NULL );
// Create memory for data
pBuffer->usNumberOfObjects = hImage->usNumberOfObjects;
// Create buffer for objects
pBuffer->pETRLEObject = (ETRLEObject *) MemAlloc( sizeof( ETRLEObject ) * pBuffer->usNumberOfObjects );
if(!pBuffer->pETRLEObject)
{
return false;
}
CHECKF( pBuffer->pETRLEObject != NULL );
memset( pBuffer->pETRLEObject, 0, sizeof( ETRLEObject ) * pBuffer->usNumberOfObjects );
// Copy into buffer
memcpy( pBuffer->pETRLEObject, hImage->pETRLEObject, sizeof( ETRLEObject ) * pBuffer->usNumberOfObjects );
// Allocate memory for pixel data
pBuffer->pPixData = MemAlloc( hImage->uiSizePixData );
if(!pBuffer->pPixData)
{
return false;
}
CHECKF( pBuffer->pPixData != NULL );
memset( pBuffer->pPixData, 0, hImage->uiSizePixData );
pBuffer->uiSizePixData = hImage->uiSizePixData;
// Copy into buffer
memcpy( pBuffer->pPixData, hImage->pPixData8, pBuffer->uiSizePixData );
return( TRUE );
}
void ConvertRGBDistribution565To555( UINT16 * p16BPPData, UINT32 uiNumberOfPixels )
{
UINT16 * pPixel;
UINT32 uiLoop;
SplitUINT32 Pixel;
pPixel = p16BPPData;
for (uiLoop = 0; uiLoop < uiNumberOfPixels; uiLoop++)
{
// If the pixel is completely black, don't bother converting it -- DB
if(*pPixel!=0)
{
// we put the 16 pixel bits in the UPPER word of uiPixel, so that we can
// right shift the blue value (at the bottom) into the LOWER word to protect it
Pixel.usHigher = *pPixel;
Pixel.uiValue >>= 5;
// get rid of the least significant bit of green
Pixel.usHigher >>= 1;
// now shift back into the upper word
Pixel.uiValue <<= 5;
// and copy back
*pPixel = Pixel.usHigher | gusAlphaMask;
}
pPixel++;
}
}
void ConvertRGBDistribution565To655( UINT16 * p16BPPData, UINT32 uiNumberOfPixels )
{
UINT16 * pPixel;
UINT32 uiLoop;
SplitUINT32 Pixel;
pPixel = p16BPPData;
for (uiLoop = 0; uiLoop < uiNumberOfPixels; uiLoop++)
{
// we put the 16 pixel bits in the UPPER word of uiPixel, so that we can
// right shift the blue value (at the bottom) into the LOWER word to protect it
Pixel.usHigher = *pPixel;
Pixel.uiValue >>= 5;
// get rid of the least significant bit of green
Pixel.usHigher >>= 1;
// shift to the right some more...
Pixel.uiValue >>= 5;
// so we can left-shift the red value alone to give it an extra bit
Pixel.usHigher <<= 1;
// now shift back and copy
Pixel.uiValue <<= 10;
*pPixel = Pixel.usHigher;
pPixel++;
}
}
void ConvertRGBDistribution565To556( UINT16 * p16BPPData, UINT32 uiNumberOfPixels )
{
UINT16 * pPixel;
UINT32 uiLoop;
SplitUINT32 Pixel;
pPixel = p16BPPData;
for (uiLoop = 0; uiLoop < uiNumberOfPixels; uiLoop++)
{
// we put the 16 pixel bits in the UPPER word of uiPixel, so that we can
// right shift the blue value (at the bottom) into the LOWER word to protect it
Pixel.usHigher = *pPixel;
Pixel.uiValue >>= 5;
// get rid of the least significant bit of green
Pixel.usHigher >>= 1;
// shift back into the upper word
Pixel.uiValue <<= 5;
// give blue an extra bit (blank in the least significant spot)
Pixel.usHigher <<= 1;
// copy back
*pPixel = Pixel.usHigher;
pPixel++;
}
}
void ConvertRGBDistribution565ToAny( UINT16 * p16BPPData, UINT32 uiNumberOfPixels )
{
UINT16 * pPixel;
UINT32 uiRed, uiGreen, uiBlue, uiTemp, uiLoop;
pPixel = p16BPPData;
for (uiLoop = 0; uiLoop < uiNumberOfPixels; uiLoop++)
{
// put the 565 RGB 16-bit value into a 32-bit RGB value
uiRed = (*pPixel) >> 11;
uiGreen = (*pPixel & 0x07E0) >> 5;
uiBlue = (*pPixel & 0x001F);
uiTemp = FROMRGB(uiRed,uiGreen,uiBlue);
// then convert the 32-bit RGB value to whatever 16 bit format is used
*pPixel = Get16BPPColor( uiTemp );
pPixel++;
}
}