mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
DirtySDK (EA's Dirty Sockets library) will be used for the LiveAPI implementation, and depends on: EABase, EAThread.
416 lines
15 KiB
C
416 lines
15 KiB
C
/*H********************************************************************************/
|
|
/*!
|
|
\File dirtygraph.c
|
|
|
|
\Description
|
|
Routines for decoding an encoded graphics image.
|
|
|
|
\Copyright
|
|
Copyright (c) 2006-2020 Electronic Arts Inc.
|
|
|
|
\Version 03/09/2006 (jbrookes) First Version
|
|
*/
|
|
/********************************************************************************H*/
|
|
|
|
/*** Include files ****************************************************************/
|
|
|
|
#include <string.h>
|
|
|
|
#include "DirtySDK/platform.h"
|
|
#include "DirtySDK/dirtysock/dirtylib.h"
|
|
#include "DirtySDK/dirtysock/dirtymem.h"
|
|
|
|
#include "DirtySDK/graph/dirtygraph.h"
|
|
#include "DirtySDK/graph/dirtygif.h"
|
|
#include "DirtySDK/graph/dirtyjpg.h"
|
|
#include "DirtySDK/graph/dirtypng.h"
|
|
|
|
/*** Defines **********************************************************************/
|
|
|
|
/*** Type Definitions *************************************************************/
|
|
|
|
typedef struct DirtyGraphBufferT
|
|
{
|
|
uint8_t *pBuffer;
|
|
int32_t iBufWidth;
|
|
int32_t iBufHeight;
|
|
} DirtyGraphBufferT;
|
|
|
|
struct DirtyGraphRefT
|
|
{
|
|
//! module memory group
|
|
int32_t iMemGroup;
|
|
void *pMemGroupUserData;
|
|
|
|
DirtyGifHdrT *pGifFrameInfo;
|
|
DirtyGraphBufferT GifImage8;
|
|
DirtyJpgStateT *pJpg;
|
|
DirtyPngStateT *pPng;
|
|
DirtyGifHdrT GifHdr;
|
|
DirtyJpgHdrT JpgHdr;
|
|
DirtyPngHdrT PngHdr;
|
|
};
|
|
|
|
/*** Variables ********************************************************************/
|
|
|
|
/*** Private Functions ************************************************************/
|
|
|
|
/*** Public functions *************************************************************/
|
|
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function DirtyGraphCreate
|
|
|
|
\Description
|
|
Create the DirtyGraph module.
|
|
|
|
\Output
|
|
DirtyGraphStateT * - module state, or NULL if unable to create
|
|
|
|
\Version 03/09/2006 (jbrookes) First Version
|
|
*/
|
|
/********************************************************************************F*/
|
|
DirtyGraphRefT *DirtyGraphCreate(void)
|
|
{
|
|
DirtyGraphRefT *pDirtyGraph;
|
|
int32_t iMemGroup;
|
|
void *pMemGroupUserData;
|
|
|
|
// Query current mem group data
|
|
DirtyMemGroupQuery(&iMemGroup, &pMemGroupUserData);
|
|
|
|
// allocate and init module state
|
|
if ((pDirtyGraph = DirtyMemAlloc(sizeof(*pDirtyGraph), DIRTYGRAPH_MEMID, iMemGroup, pMemGroupUserData)) == NULL)
|
|
{
|
|
NetPrintf(("dirtygraph: could not allocate module state\n"));
|
|
return(NULL);
|
|
}
|
|
ds_memclr(pDirtyGraph, sizeof(*pDirtyGraph));
|
|
pDirtyGraph->iMemGroup = iMemGroup;
|
|
pDirtyGraph->pMemGroupUserData = pMemGroupUserData;
|
|
|
|
// allocate jpeg module state
|
|
if ((pDirtyGraph->pJpg = DirtyJpgCreate()) == NULL)
|
|
{
|
|
NetPrintf(("dirtygraph: unable to allocate jpg module state\n"));
|
|
}
|
|
|
|
// allocate png module state
|
|
if ((pDirtyGraph->pPng = DirtyPngCreate()) == NULL)
|
|
{
|
|
NetPrintf(("dirtygraph: unable to allocate png module state\n"));
|
|
}
|
|
|
|
// return module state ref
|
|
return(pDirtyGraph);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function DirtyGraphDestroy
|
|
|
|
\Description
|
|
Destroy the DirtyGraph module.
|
|
|
|
\Input *pDirtyGraph - pointer to module state
|
|
|
|
\Output
|
|
None.
|
|
|
|
\Version 03/09/2006 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void DirtyGraphDestroy(DirtyGraphRefT *pDirtyGraph)
|
|
{
|
|
// destroy gif 8bit frame buffer?
|
|
if (pDirtyGraph->GifImage8.pBuffer != NULL)
|
|
{
|
|
DirtyMemFree(pDirtyGraph->GifImage8.pBuffer, DIRTYGRAPH_MEMID, pDirtyGraph->iMemGroup, pDirtyGraph->pMemGroupUserData);
|
|
}
|
|
// destroy gif frame info?
|
|
if (pDirtyGraph->pGifFrameInfo != NULL)
|
|
{
|
|
DirtyMemFree(pDirtyGraph->pGifFrameInfo, DIRTYGRAPH_MEMID, pDirtyGraph->iMemGroup, pDirtyGraph->pMemGroupUserData);
|
|
}
|
|
// destroy jpeg module?
|
|
if (pDirtyGraph->pJpg != NULL)
|
|
{
|
|
DirtyJpgDestroy(pDirtyGraph->pJpg);
|
|
}
|
|
// destroy png module?
|
|
if (pDirtyGraph->pPng != NULL)
|
|
{
|
|
DirtyPngDestroy(pDirtyGraph->pPng);
|
|
}
|
|
// free module state
|
|
DirtyMemFree(pDirtyGraph, DIRTYGRAPH_MEMID, pDirtyGraph->iMemGroup, pDirtyGraph->pMemGroupUserData);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function DirtyGraphDecodeHeader
|
|
|
|
\Description
|
|
Decode an image header
|
|
|
|
\Input *pDirtyGraph - pointer to module state
|
|
\Input *pInfo - [out] storage for image info
|
|
\Input *pImageData - pointer to input image info
|
|
\Input uImageLen - size of input image
|
|
|
|
\Output
|
|
int32_t - negative=error, else success
|
|
|
|
\Version 03/09/2006 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t DirtyGraphDecodeHeader(DirtyGraphRefT *pDirtyGraph, DirtyGraphInfoT *pInfo, const uint8_t *pImageData, uint32_t uImageLen)
|
|
{
|
|
int32_t iError, iResult=-1;
|
|
|
|
// init info structure
|
|
ds_memclr(pInfo, sizeof(*pInfo));
|
|
pInfo->pImageData = pImageData;
|
|
pInfo->uLength = uImageLen;
|
|
|
|
// try and identify image
|
|
if (DirtyGifIdentify(pImageData, uImageLen))
|
|
{
|
|
if ((iError = DirtyGifParse(&pDirtyGraph->GifHdr, pImageData, pImageData+uImageLen)) == 0)
|
|
{
|
|
pInfo->uType = DIRTYGRAPH_IMAGETYPE_GIF;
|
|
pInfo->iWidth = pDirtyGraph->GifHdr.uWidth;
|
|
pInfo->iHeight = pDirtyGraph->GifHdr.uHeight;
|
|
pInfo->uNumFrames = pDirtyGraph->GifHdr.uNumFrames;
|
|
// if we have a previous gif frame buffer, destroy it now
|
|
if (pDirtyGraph->pGifFrameInfo != NULL)
|
|
{
|
|
DirtyMemFree(pDirtyGraph->pGifFrameInfo, DIRTYGRAPH_MEMID, pDirtyGraph->iMemGroup, pDirtyGraph->pMemGroupUserData);
|
|
}
|
|
// now allocate and parse frame data
|
|
if ((pDirtyGraph->pGifFrameInfo = DirtyMemAlloc(sizeof(*pDirtyGraph->pGifFrameInfo)*pInfo->uNumFrames, DIRTYGRAPH_MEMID, pDirtyGraph->iMemGroup, pDirtyGraph->pMemGroupUserData)) != NULL)
|
|
{
|
|
iResult = DirtyGifParseEx(&pDirtyGraph->GifHdr, pImageData, pImageData+uImageLen, pDirtyGraph->pGifFrameInfo, pInfo->uNumFrames);
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("dirtygraph: unable to allocate memory for gif frames list\n"));
|
|
iResult = -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("dirtygraph: error %d parsing gif image\n", iError));
|
|
}
|
|
|
|
}
|
|
else if ((pDirtyGraph->pJpg != NULL) && DirtyJpgIdentify(pDirtyGraph->pJpg, pImageData, uImageLen))
|
|
{
|
|
if ((iError = DirtyJpgDecodeHeader(pDirtyGraph->pJpg, &pDirtyGraph->JpgHdr, pImageData, uImageLen)) == DIRTYJPG_ERR_NONE)
|
|
{
|
|
pInfo->uType = DIRTYGRAPH_IMAGETYPE_JPG;
|
|
pInfo->iWidth = pDirtyGraph->JpgHdr.uWidth;
|
|
pInfo->iHeight = pDirtyGraph->JpgHdr.uHeight;
|
|
pInfo->uNumFrames = 1;
|
|
iResult = 0;
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("dirtygraph: error %d parsing jpg image\n", iError));
|
|
}
|
|
}
|
|
else if ((pDirtyGraph->pPng != NULL) && DirtyPngIdentify(pImageData, uImageLen))
|
|
{
|
|
if ((iError = DirtyPngParse(pDirtyGraph->pPng, &pDirtyGraph->PngHdr, pImageData, pImageData+uImageLen)) == DIRTYPNG_ERR_NONE)
|
|
{
|
|
pInfo->uType = DIRTYGRAPH_IMAGETYPE_PNG;
|
|
pInfo->iWidth = pDirtyGraph->PngHdr.uWidth;
|
|
pInfo->iHeight = pDirtyGraph->PngHdr.uHeight;
|
|
pInfo->uNumFrames = 1;
|
|
iResult = 0;
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("dirtygraph: error %d parsing png image\n", iError));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("dirtygraph: cannot parse image of unknown type\n"));
|
|
pInfo->uType = DIRTYGRAPH_IMAGETYPE_UNKNOWN;
|
|
pInfo->pImageData = NULL;
|
|
pInfo->uLength = 0;
|
|
}
|
|
|
|
// return result to caller
|
|
return(iResult);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function DirtyGraphGetImageInfo
|
|
|
|
\Description
|
|
Get extended information about an image
|
|
|
|
\Input *pDirtyGraph - pointer to module state
|
|
\Input *pInfo - image information (filled in by DirtyGraphDecodeHeader)
|
|
\Input iSelect - info selector
|
|
\Input *pBuffer - [out] selector output
|
|
\Input iBufSize - size of output buffer
|
|
|
|
\Output
|
|
int32_t - selector return
|
|
|
|
\Notes
|
|
Selectors are:
|
|
|
|
\verbatim
|
|
'anim' fills buffer with int32_t anim info (delay) in milliseconds, and returns number of frames
|
|
\endverbatim
|
|
|
|
\Version 01/27/2020 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t DirtyGraphGetImageInfo(DirtyGraphRefT *pDirtyGraph, DirtyGraphInfoT *pInfo, int32_t iSelect, void *pBuffer, int32_t iBufSize)
|
|
{
|
|
if ((iSelect == 'anim') && (pInfo->uType == DIRTYGRAPH_IMAGETYPE_GIF) && (pBuffer != NULL) && (iBufSize == (signed)(pInfo->uNumFrames*sizeof(int32_t))))
|
|
{
|
|
int32_t *pDelayBuf = (int32_t *)pBuffer, iFrame;
|
|
// collect delay info in integer output array
|
|
for (iFrame = 0; iFrame < pInfo->uNumFrames; iFrame += 1)
|
|
{
|
|
pDelayBuf[iFrame] = pDirtyGraph->pGifFrameInfo[iFrame].uDelay;
|
|
}
|
|
// return count of delay frame values copied to output buffer
|
|
return(iFrame);
|
|
}
|
|
// unhandled
|
|
return(-1);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function DirtyGraphDecodeImage
|
|
|
|
\Description
|
|
Decode an image into the given output buffer.
|
|
|
|
\Input *pDirtyGraph - pointer to module state
|
|
\Input *pInfo - image information (filled in by DirtyGraphDecodeHeader)
|
|
\Input *pImageBuf - [out] pointer to buffer to store decoded image
|
|
\Input iBufWidth - width of output buffer
|
|
\Input iBufHeight - height of output buffer
|
|
|
|
\Output
|
|
int32_t - negative=error, else success
|
|
|
|
\Version 03/09/2006 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t DirtyGraphDecodeImage(DirtyGraphRefT *pDirtyGraph, DirtyGraphInfoT *pInfo, uint8_t *pImageBuf, int32_t iBufWidth, int32_t iBufHeight)
|
|
{
|
|
if (pInfo->uType == DIRTYGRAPH_IMAGETYPE_GIF)
|
|
{
|
|
return(DirtyGifDecodeImage32Multi(&pDirtyGraph->GifHdr, pDirtyGraph->pGifFrameInfo, pImageBuf, iBufWidth, iBufHeight, 1, TRUE));
|
|
}
|
|
else if (pInfo->uType == DIRTYGRAPH_IMAGETYPE_JPG)
|
|
{
|
|
return(DirtyJpgDecodeImage(pDirtyGraph->pJpg, &pDirtyGraph->JpgHdr, pImageBuf, iBufWidth, iBufHeight));
|
|
}
|
|
else if (pInfo->uType == DIRTYGRAPH_IMAGETYPE_PNG)
|
|
{
|
|
return(DirtyPngDecodeImage(pDirtyGraph->pPng, &pDirtyGraph->PngHdr, pImageBuf, iBufWidth, iBufHeight));
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("dirtygraph: cannot decode image of unknown type\n"));
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function DirtyGraphDecodeImageMulti
|
|
|
|
\Description
|
|
Decode a multiframe image into an array of images in the given output buffer.
|
|
|
|
\Input *pDirtyGraph - pointer to module state
|
|
\Input *pInfo - image information (filled in by DirtyGraphDecodeHeader)
|
|
\Input *pImageBuf - [out] pointer to buffer to store decoded images
|
|
\Input iBufWidth - width of output buffer
|
|
\Input iBufHeight - height of output buffer
|
|
|
|
\Output
|
|
int32_t - negative=error, else success
|
|
|
|
\Version 01/28/2020 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t DirtyGraphDecodeImageMulti(DirtyGraphRefT *pDirtyGraph, DirtyGraphInfoT *pInfo, uint8_t *pImageBuf, int32_t iBufWidth, int32_t iBufHeight)
|
|
{
|
|
if ((pInfo->uType == DIRTYGRAPH_IMAGETYPE_GIF) && (pDirtyGraph->pGifFrameInfo != NULL))
|
|
{
|
|
return(DirtyGifDecodeImage32Multi(&pDirtyGraph->GifHdr, pDirtyGraph->pGifFrameInfo, pImageBuf, iBufWidth, iBufHeight, pDirtyGraph->GifHdr.uNumFrames, TRUE));
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("dirtygraph: multi-image decoding not supported for image type\n"));
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function DirtyGraphDecodeImageFrame
|
|
|
|
\Description
|
|
Decode a multiframe image into the given output buffer. The frame order must
|
|
be from the first frame to the last in sequence and the image data output
|
|
buffer must be preserved between calls, except when decoding the first frame.
|
|
|
|
\Input *pDirtyGraph - pointer to module state
|
|
\Input *pInfo - image information (filled in by DirtyGraphDecodeHeader)
|
|
\Input *pImageBuf - [out] pointer to buffer to store decoded image
|
|
\Input iBufWidth - width of output buffer
|
|
\Input iBufHeight - height of output buffer
|
|
\Input iFrame - frame to decode
|
|
|
|
\Output
|
|
int32_t - negative=error, else success
|
|
|
|
\Version 02/06/2020 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t DirtyGraphDecodeImageFrame(DirtyGraphRefT *pDirtyGraph, DirtyGraphInfoT *pInfo, uint8_t *pImageBuf, int32_t iBufWidth, int32_t iBufHeight, int32_t iFrame)
|
|
{
|
|
if ((pInfo->uType == DIRTYGRAPH_IMAGETYPE_GIF) && (pDirtyGraph->pGifFrameInfo != NULL))
|
|
{
|
|
// if eight-bit frame cache exists but the frame size has changed, kill it
|
|
if ((pDirtyGraph->GifImage8.pBuffer != NULL) && ((pDirtyGraph->GifImage8.iBufWidth != iBufWidth) || (pDirtyGraph->GifImage8.iBufHeight != iBufHeight)))
|
|
{
|
|
DirtyMemFree(pDirtyGraph->GifImage8.pBuffer, DIRTYGRAPH_MEMID, pDirtyGraph->iMemGroup, pDirtyGraph->pMemGroupUserData);
|
|
pDirtyGraph->GifImage8.pBuffer = NULL;
|
|
}
|
|
// allocate eight-bit frame cache
|
|
if (pDirtyGraph->GifImage8.pBuffer == NULL)
|
|
{
|
|
if ((pDirtyGraph->GifImage8.pBuffer = DirtyMemAlloc(iBufWidth * iBufHeight, DIRTYGRAPH_MEMID, pDirtyGraph->iMemGroup, pDirtyGraph->pMemGroupUserData)) == NULL)
|
|
{
|
|
NetPrintf(("dirtygraph: could not allocate 8bit decode buffer\n"));
|
|
return(-1);
|
|
}
|
|
pDirtyGraph->GifImage8.iBufWidth = iBufWidth;
|
|
pDirtyGraph->GifImage8.iBufHeight = iBufHeight;
|
|
}
|
|
// decode the frame and return result to caller
|
|
return(DirtyGifDecodeImage32Frame(&pDirtyGraph->GifHdr, pDirtyGraph->pGifFrameInfo, pImageBuf, pDirtyGraph->GifImage8.pBuffer, iBufWidth, iBufHeight, iFrame, pDirtyGraph->GifHdr.uNumFrames, TRUE));
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("dirtygraph: multi-image decoding not supported for image type\n"));
|
|
return(-1);
|
|
}
|
|
} |