Code Search for Developers
 
 
  

GfxDecode.cpp from MaNGOS at Krugle


Show GfxDecode.cpp syntax highlighted

/***********************************************************************
*
* Description:  GfxDecode -- functions for reading Diablo's GFX files
* Author: Marko Friedemann <marko.friedemann@bmx-chemnitz.de>
* Created at: Son Jan 27 15:20:43 CET 2002
* Computer: hangloose.flachland-chemnitz.de 
* System: Linux 2.4.16 on i686
*    
* Copyright (c) 2002  BMX-Chemnitz.DE  All rights reserved.
*
* ---------------------------------------------------------------------
* included are functions for getting:
*  - the framecount of .CEL-files                  -> celGetFrameCount()
*  - single frames of .CEL-files                   -> celGetFrameData()
*  - the framecount of .CL2-files                  -> cl2GetFrameCount()
*  - single directions of .CL2-files (all frames)  -> cl2GetDirData()
*  - single .PCX-files (256 color; v2, v5)         -> pcxGetData()
***********************************************************************/

#include <vector>
#include <cmath>
#include <iostream>

#include "StormLib.h"

#define TRANS_COL 256

using std::cerr;
using std::vector;

/****** RAMP stuff *****************************************************
 * for a more detailed description/explanation see below
 ***********************************************************************/
// two variations: one/two ramp(s)
static const uint16_t c_2RampSize = 544;    // the frame size
static const uint16_t c_1RampSize = 800;    // the frame size

// ramps (both variations) can be either left or right
static const uint16_t c_RampOffsetLeft[17] = {
    0,      //                                      __
    8,      // +  8     note that this          __--
    24,     // + 16     "drawing" is        __--
    48,     // + 24     upside down!    __--    this area
    80,     // + 32                 __--        is always
    120,    // + 40             __--            colored
    168,    // + 48         __--
    224,    // + 56     __--  lower ramp ends here (+30 == 254)
    288,    // + 64   --__    upper ramp might be missing
    348,    // + 60   |   --__
    400,    // + 52   |       --__              this area
    444,    // + 44   |           --__          is always
    480,    // + 36   |               --__      colored
    508,    // + 28   | either trans-     --__
    528,    // + 20   | parent or colored     --__
    540,    // + 12   |                           --__   +2 Pixels = 544
    542     // +  2   | this last one doesn't exist, it's those^ 2 pixels
};

static const uint16_t c_RampOffsetRight[17] = {
    2,      //        __         before this, there are 2 Pixels
    14,     // + 12     --__              4^2 - 2
    34,     // + 20         --__          6^2 - 2
    62,     // + 28  this area  --__      8^2 - 2 
    98,     // + 36  is always      --__ 10^2 - 2  pattern anyone? ;)
    142,    // + 44  colored            --__ 
    194,    // + 52                         --__
    254,    // + 60  lower ramp ends here       --__     (-30 == 224)
    318,    // + 64  upper ramp might be missing  __--   
    374,    // + 56                           __--   |
    422,    // + 48  this area            __--       |   note that this
    462,    // + 40  is always        __--           |   "drawing"
    494,    // + 32  colored      __--  eiter trans- |   is upside down!
    518,    // + 24           __-- parent or colored |
    534,    // + 16       __--                       |
    542,    // +  8   __--   +2 Startpixels = 544    |
    542     // +  0  this last one doesn't exist, it |   would be EOF
};

/****** FrameBuffer class **********************************************
 * holds buffers and size information of the actual target image
 *  purpose: buffer management and avoidance of ugly globals
 **********************************************************************/
class FrameBuf
{
 protected:
    vector <uint8_t *> vecData;
    uint8_t  *pCurrRow;
    uint8_t  *pPalette;
    uint16_t  uRows;
    uint16_t *upYSize;
    uint16_t *upMaxX;
 public:
    uint16_t  uCols;
    uint16_t  uXSize;
    uint16_t  uMaxBlock;
    uint16_t  uFrameNum;
    bool      bHasBlocks;
    bool      bHasRamps;
    FrameBuf(
        uint8_t *pPal=NULL, uint16_t frame=0, uint16_t xsize=0,
        uint16_t *pysize=NULL, uint16_t *pmaxx=NULL, uint16_t maxblock=0)
    {
        pCurrRow  = new uint8_t[4*xsize];
        pPalette  = pPal;
        uCols     = 0;
        uRows     = 0;
        uXSize    = xsize;
        uFrameNum = frame;
        uMaxBlock = maxblock;
        upYSize   = pysize;
        upMaxX    = pmaxx;
        bHasBlocks= false;
        bHasRamps = false;
    }
    ~FrameBuf()
    {
        delete[] pCurrRow;
        for (vector <uint8_t *>::iterator vi=vecData.begin(); vi!=vecData.end(); vi++)
            delete[] *vi;
        vecData.clear();
    }
    void addLine()
    {
        ++uRows;
        uCols = 0;
        vecData.push_back(pCurrRow);
        pCurrRow = new uint8_t[4*uXSize];
    }
    void addPixel(uint16_t uColorNum)
    {
        if (uColorNum > TRANS_COL) {
            cerr << "\n*** there seemed to be an error, illegal color index " << uColorNum;
            cerr << "\n +++ at (" << uCols << "," << uRows << "), see for yourself *** \n\n";
            uColorNum = TRANS_COL;      // sane setting to avoid segfaults
        }
        
        memcpy(pCurrRow + 4*uCols, pPalette + 4*uColorNum, 4*sizeof(uint8_t));
        if (++uCols == uXSize)
            addLine();
        else if ((uColorNum != TRANS_COL) && (upMaxX != NULL) && (uCols > *upMaxX))
            *upMaxX = uCols;
    }
    // used to return the actual image data
    uint8_t *getData()
    {
        uint16_t i;
        vector <uint8_t *>::reverse_iterator vri;
        // allocate a buffer to hold the actual image size
        uint8_t *tmp = new uint8_t[4*uXSize*uRows];
        
        // the lines are upside down inside the vector, use reverse iterator
        for (i=0, vri=vecData.rbegin(); vri!=vecData.rend(); vri++, i++)
            memcpy(tmp+4*uXSize*i, *vri, 4*uXSize*sizeof(uint8_t));
        
        *upYSize = uRows;    // set height
        
        if (uCols > 0) {
            cerr << "\n*** there seemed to be an error (last line does not match boundary, " << uCols << " pixels left)";
            cerr << "\n +++ this is often caused by specifying an invalid width, see for yourself *** \n\n";
        }
        
        return tmp;
    }
};

uint16_t WINAPI celGetFrameCount(uint8_t *pFileBuf)
{
    uint32_t tmp;
    memcpy(&tmp, pFileBuf, sizeof(uint32_t));
    return (uint16_t)tmp;
}

/***** Block Decoder ***************************************************
 * one of three possible decoding techniques necessary for .cel
 *  possible block contents are either colored (in that case the
 *  appropriate number of pixels are read) or transparent pixels
 *  there are neither ramps nor plain pixels allowed here
 ***********************************************************************/
uint8_t *celDecodeBlocks(uint8_t *pFileBuf, FrameBuf *pFrame, uint32_t *framestart)
{
    uint32_t uFilePos=framestart[pFrame->uFrameNum];
    uint8_t cRead=0, i=0;

    if (!pFrame->bHasBlocks)      // sanity check
        return NULL;
        
    while (uFilePos < framestart[pFrame->uFrameNum+1]) {
        cRead = pFileBuf[uFilePos++];
        
        if ((uFilePos == framestart[pFrame->uFrameNum]+1))
            // TODO: what is this 0x0A 0x00 stuff all about?
            if ((cRead == 0x0A) && (pFileBuf[uFilePos] == 0x00)) {
                uFilePos += 9;
                cRead = pFileBuf[uFilePos++];
            }
    
        if (cRead > 0x7F)
            // transparent block (complement, 256-val)
            for (i=0; i<256-cRead; i++)
                pFrame->addPixel(TRANS_COL);
        else if (cRead < pFrame->uMaxBlock + 1)
                // pixel block (block size pixels to be read!)
                for (i=0; i<cRead; i++)
                    pFrame->addPixel(pFileBuf[uFilePos++]);
        else
            cerr << "\n*** block mode: illegal block (> max_size) ***\n\n";
    }
    return pFrame->getData();
}

/***** Ramp Decoder ****************************************************
 * the second of three possible decoding techniques necessary for .cel
 *  each block save the first/last is enclosed by two 0x00 pairs
 *  those blocks affect _TWO_ rows with one being 2 colored pixels shorter
 *  the first/last "block" affects only one row
 ***********************************************************************/
uint8_t *celDecodeRamps(uint8_t *pFileBuf, FrameBuf *pFrame, uint32_t *framestart, bool bLeft)
{
    uint32_t uFrameLen = framestart[pFrame->uFrameNum+1]-framestart[pFrame->uFrameNum];
    uint32_t uFilePos=0;
    uint16_t uBlockLen=0, i=0, j=0;
    bool bFirstLonger=false;
    
    if (!pFrame->bHasRamps)     // sanity check
        return NULL;
        
    if (pFrame->uXSize != 32)   // only used in that case
        return NULL;

    if (!bLeft) { // get first two pixels for right side ramps
        pFrame->addPixel(pFileBuf[framestart[pFrame->uFrameNum]]);
        pFrame->addPixel(pFileBuf[framestart[pFrame->uFrameNum]+1]);
    }

    // do all the ramp blocks
    for (i=0; i<(uFrameLen == c_2RampSize ? 15 : 7); i++) {
        uBlockLen = (bLeft ? (c_RampOffsetLeft[i+1] - c_RampOffsetLeft[i]) : (c_RampOffsetRight[i+1] - c_RampOffsetRight[i]));
        uFilePos = framestart[pFrame->uFrameNum] + (bLeft ? c_RampOffsetLeft[i] : c_RampOffsetRight[i]) + 2;
        bFirstLonger = (i>(bLeft ? 7 : 6));
        if (bLeft) {
            // OK, first line, starting with transparency
            for (j=0; j<pFrame->uXSize - uBlockLen/2 + (bFirstLonger ? 0 : 2); j++)
                pFrame->addPixel(TRANS_COL);
            // fill it up with the pixel block
            for (j=0; j<uBlockLen/2 - (bFirstLonger ? 0 : 2); j++)
                pFrame->addPixel(pFileBuf[uFilePos++]);
            // second line, starting again with transparency
            for (j=0; j<pFrame->uXSize - uBlockLen/2 + (bFirstLonger ? 2 : 0); j++)
                pFrame->addPixel(TRANS_COL);
            // fill the second line with the remaining pixels
            for (j=0; j<uBlockLen/2 - (bFirstLonger ? 2 : 0); j++)
                pFrame->addPixel(pFileBuf[uFilePos++]);
        } else {
            if (pFrame->uCols != 0) // fill current line with trans (if not empty)
                for (j=pFrame->uXSize - pFrame->uCols; j>0; j--)
                    pFrame->addPixel(TRANS_COL);
            // OK, insert the first pixels into a new line
            for (j=0; j<uBlockLen/2 - (bFirstLonger ? 0 : 2); j++)
                pFrame->addPixel(pFileBuf[uFilePos++]);
            // fill the line with transparency
            for (j=0; j<pFrame->uXSize - uBlockLen/2 + (bFirstLonger ? 0 : 2); j++)
                pFrame->addPixel(TRANS_COL);
            // start a second line with the remaining pixels
            for (j=0; j<uBlockLen/2 - (bFirstLonger ? 2 : 0); j++)
                pFrame->addPixel(pFileBuf[uFilePos++]);
        }
    }
    
    // now read the last 0x00 pair and fill up
    uBlockLen = (uFrameLen == c_2RampSize ? 30 : 2); // one or two ramps?
    uFilePos = framestart[pFrame->uFrameNum] + (bLeft ? c_RampOffsetLeft[i] : c_RampOffsetRight[i]) + 2;
    // the transparency for the last (single) 0x00 pair
    for (j=0; j<uBlockLen; j++)
        pFrame->addPixel(TRANS_COL);
    if (bLeft) {  // left side only: the remaining line
        for (j=0; j<pFrame->uXSize - uBlockLen; j++)
            pFrame->addPixel(pFileBuf[uFilePos++]);
    }
    
    // now the rest of the file (plain)
    while (uFilePos < framestart[pFrame->uFrameNum+1])
        pFrame->addPixel(pFileBuf[uFilePos++]);
    
    // the uppermost line is emtpy when 2 ramps are used
    if (uFrameLen == c_2RampSize)
        for (j=0; j<pFrame->uXSize; j++)
            pFrame->addPixel(TRANS_COL);
            
    return pFrame->getData();
}

/***** celGetFrameData *************************************************
 *             decode .cel data for given frame and xsize
 * Args:
 *     *vpFileBuf       the buffer containing the filecontent
 *     *palette         the palette (4 bytes for each of the 257 entries)
 *                        256 colors are needed + 1 for alpha
 *      uXSize          this information must be given
 *      uFrameNume      the frame to get
 *     *uYSize          the actual value is returned therein
 *     *uMaxX           this can be used (if != NULL) to get the column
 *                      of the rightmost nontransparent pixel (useable
 *                      eg for fonts)
 *
 * Returns: an array containing 4 Bytes (RGBA) for each pixel
 *
 * ---------------------------------------------------------------
 * Comments:     dirty hack, started from scratch @ 2000-10-11
 *               cleanly rewritten during incorporation into ladiks StormLib
 *      status:  structured hack ;)
 *   
 *   It took me approx. 6 days to understand the format basics (hex viewer)
 *   For this I had a little help from a dos tool ("ddecode", from
 *   www.cowlevel.com, binary only, no sources) which, however, gave 
 *   me the general idea what the pictures are actually supposed to look like.
 *   
 *   The fine adjustments, however, took quite some time and a little luck.
 *   After I had written to various people (mickyk and ladik), which could
 *   not help me, but wished best luck (thanks, btw, it helped ;)), I tried
 *   some reverse engineering which was not succesful in the end.
 *   
 *   I then had incidentally a new idea of what could be going on @ 2002-01-23.
 *   It just came to my mind that I could retry some actual painting in
 *   reverse order (had done that before to no avail) and when looking closer
 *   at it I realized the "ramp" stuff. This really is the trickiest part and
 *   it took me some eight days to implement it without breaking the other
 *   parts of the code. Very odd format indeed.
 *
 * TODO: learn what 0x0A 0x00 means
 **********************************************************************/
uint8_t * WINAPI celGetFrameData(uint8_t *pFileBuf, uint8_t *palette, uint16_t uXSize, uint16_t uFrameNum, uint16_t *uYSize, uint16_t *uMaxX)
{
    FrameBuf *pFrame;
    uint32_t *framestart=NULL, frames=0, uFilePos=0;
    uint16_t i, tmpWord=0;
    uint8_t cRead=0, *data;
    
    memcpy(&frames, pFileBuf, sizeof(uint32_t));
    uFilePos += sizeof(uint32_t);
    
    if (pFileBuf == NULL) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }
    
    if (palette == NULL) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }
    
    if (uFrameNum > frames-1) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }
        
    if (uYSize == NULL) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }
        
    // in case we want to know the rightmost pixels column (usable eg. for fonts)
    if (uMaxX != NULL)
        *uMaxX = 0;
    
    // get the frame offsets
    framestart = new uint32_t[frames+1];
    for (i=0; i<frames+1; i++) {
        memcpy(&framestart[i], pFileBuf+uFilePos, sizeof(uint32_t));
        uFilePos += sizeof(uint32_t);
    }
    
    /****** block size *************************************************
     * depends on the image width
     ******************************/
    
    double erg = rint(sqrt(pow(2, rint(log((double)(framestart[uFrameNum+1] - framestart[uFrameNum])) / log(2.0)))));
    pFrame = new FrameBuf(palette, uFrameNum, uXSize, uYSize, uMaxX, max((uint16_t)min((int)erg, 0x7F), uXSize));
    
    /****** ramp detection -- AFAIK only needed for 32x32 tiles ********
     * here I use hard coded constants because this is the only simple
     * way to get the detection done; plus this stuff is only to be
     * found in such 32x32 (tile) files and so wont hurt anyone ;)
     ******************************************************************/

    uint32_t uFrameLen = framestart[uFrameNum+1] - framestart[uFrameNum];
    if ((uXSize == 32) && ((uFrameLen == c_2RampSize) || (uFrameLen == c_1RampSize))) {

        // use the static arrays for the check        
        for (i=0; i<(uFrameLen == c_2RampSize ? 16 : 8); i++) {
            memcpy(&tmpWord, pFileBuf+framestart[uFrameNum]+c_RampOffsetLeft[i], sizeof(uint16_t));
            if (tmpWord != 0)
                break;
        }
        bool bRampsLeft = pFrame->bHasRamps = (i==(uFrameLen == c_2RampSize ? 16 : 8));
        if (!pFrame->bHasRamps) { // only one can apply
            for (i=0; i<(uFrameLen == c_2RampSize ? 16 : 8); i++) {
                memcpy(&tmpWord, pFileBuf+framestart[uFrameNum]+c_RampOffsetRight[i], sizeof(uint16_t));
                if (tmpWord != 0)
                    break;
            }
            pFrame->bHasRamps = (i==(uFrameLen == c_2RampSize ? 16 : 8)); // bRampsLeft stays false in this case
        }
        
        if (pFrame->bHasRamps) {  // decode ramps and be off (if appropriate)
            data = celDecodeRamps(pFileBuf, pFrame, framestart, bRampsLeft);
            delete pFrame;
            delete[] framestart;
            return data;
        }
    }
    
    /*********** block detection ***************************************
     * 0x0A as start byte seems to be sufficient (though I still dunno
     * what the trailing 10 bytes mean); in any other case we act as if
     * blocks were to be used and check afterwards if the image looks
     * OK (that is, the last line has no pixels in it)
     ******************************************************************/
    
    cRead = pFileBuf[framestart[uFrameNum]];
    if (cRead == 0x0A)          // sufficient
        pFrame->bHasBlocks = true;
    // if width == 32 && framelen == 32*32, assume plain
    else if ((uXSize != 32) || (uFrameLen != 32*32)) {    // check needed
        uFilePos=framestart[uFrameNum];             
        i=0;
        // rush through the frame
        while (uFilePos < framestart[uFrameNum+1]) {
            cRead = pFileBuf[uFilePos++];
            
            // transparency blocks
            while (cRead > 0x7F) {
                i += 256-cRead;
                i %= uXSize;
                if (uFilePos < framestart[uFrameNum+1])
                    cRead = pFileBuf[uFilePos++];
                else
                    cRead = 0;
            }
            
            // colored pixel block
            if (uFilePos < framestart[uFrameNum+1]) {
                if (cRead < pFrame->uMaxBlock + 1) {
                    i+=cRead;
                    i%=uXSize;
                    uFilePos+=cRead;
                } else {
                    // when the value is out of valid blockrange
                    i=1;    // trigger error (1%uXSize != 0)
                    break;
                }
            }
        }
        if (i%uXSize == 0)      // looks as if we got it right
            pFrame->bHasBlocks=true;
    }
    
    if (pFrame->bHasBlocks) {   // use block decoder if appropriate
        data = celDecodeBlocks(pFileBuf, pFrame, framestart);
        delete pFrame;
        delete[] framestart;
        return data;
    }
        
    // plain mode (#3), read each color index and write the pixel
    uFilePos=framestart[uFrameNum];
    while (uFilePos < framestart[uFrameNum+1])
        pFrame->addPixel(pFileBuf[uFilePos++]);
    
    // cleanup, return image data and height
    data = pFrame->getData();
    delete pFrame;
    delete[] framestart;
    return data;
}

uint16_t WINAPI cl2GetFrameCount(uint8_t *pFileBuf)
{
    uint32_t tmp;
    memcpy(&tmp, pFileBuf, sizeof(uint32_t));
    memcpy(&tmp, pFileBuf+tmp, sizeof(uint32_t));
    return (uint16_t)tmp;
}

/***** cl2GetDirData ***************************************************
 *         decodes all frames of a .cl2 for given direction and xsize
 * Args:
 *     *pFileBuf        the buffer containing the filecontent
 *     *palette         the palette (4 bytes for each of the 257 entries)
 *                        256 colors are needed + 1 for alpha
 *      uXSize          this information must be given
 *      uDirNum         the direction to get the frames from
 *     *uYSize          the actual height is returned herein
 *
 * Returns: <frames> arrays containing 4 Bytes (RGBA) for each pixel
 *     where <frames> is read at runtime and handed back via *uFrames
 *
 * ---------------------------------------------------------------
 * Comments:     dirty hack, started from scratch @ 2000-10-12
 *   
 *   The format basics are similar to .cel, with the main difference
 *   that the values read have reverse interpretation. In .cel a value
 *   greater than 0x7F means transparency, while in .cl2 this means
 *   color and vice-versa. .cl2 has the additional understanding
 *   of blocks of the same color (0x80 .. 0xBF) where the one color is
 *   written multiple times.
 *
 *   .cl2 only uses the block scheme, so there is no detection
 *   necessary in order to get it right. The only thing still unknown
 *   is that 0x0A 0x00 stuff...
 *   
 * TODO: learn what 0x0A 0x00 means
 ***********************************************************************/
BYTE ** WINAPI cl2GetDirData(BYTE *pFileBuf, BYTE *palette, WORD uXSize, WORD uDirNum, WORD *uYSize)
{
    FrameBuf *pFrame;
    uint32_t frames=0, *framestart=NULL, uFilePos=0;
    uint16_t i, fc;
    uint8_t cRead=0, **data=NULL;
    
    if (pFileBuf == NULL) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }
    
    if (palette == NULL) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }
    
    if (uDirNum > 7) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }
        
    if (uYSize == NULL) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }
    
    // get direction offsets
    uint32_t dirstart[8];
    for (i=0; i<8; i++) {
        memcpy(&dirstart[i], pFileBuf+uFilePos, sizeof(uint32_t));
        uFilePos += sizeof(uint32_t);
    }

    uFilePos = dirstart[uDirNum];
    
    memcpy(&frames, pFileBuf+uFilePos, sizeof(uint32_t));
    uFilePos += sizeof(uint32_t);
    
    data = new uint8_t*[frames];
    
    // get frame offsets
    framestart = new uint32_t[frames+1];
    for (i=0; i<frames+1; i++) {
        memcpy(&framestart[i], pFileBuf+uFilePos, sizeof(uint32_t));
        uFilePos += sizeof(uint32_t);
    }
    
    // get frame data        
    for (fc=0; fc<frames; fc++) {
        pFrame = new FrameBuf(palette, 0, uXSize, uYSize, NULL, 0);
        
        uFilePos = dirstart[uDirNum] + framestart[fc];
        while (uFilePos < dirstart[uDirNum] + framestart[fc+1]) {

            cRead = pFileBuf[uFilePos++];
            if (cRead < 0x80) { // transparency
                // TODO: what is this 0x0A 0x00 stuff all about?
                if ((cRead == 0x0A) && (pFileBuf[uFilePos] == 0) && (uFilePos == dirstart[uDirNum] + framestart[fc] + 1))
                    uFilePos += 9;  // ignore the 9 bytes after 0x0A 0x00 at the framestart
                else
                    for (i=0; i<cRead; i++)
                        pFrame->addPixel(TRANS_COL);
            } else if (cRead < 0xC0) {
                // read the next byte and write it <0xBF - cRead> times
                for (i=0; i<0xBF - cRead; i++)
                    pFrame->addPixel(pFileBuf[uFilePos]);
                ++uFilePos;
            } else // cRead > 0xBF
                // read a block of the given size and write it
                for (i=0; i < 256-cRead; i++)
                    pFrame->addPixel(pFileBuf[uFilePos++]);
        }
        
        // got the frame data, save it
        data[fc] = pFrame->getData();
        delete pFrame;
    }
    
    delete[] framestart;
    return data;
}

/****** pcxGetData *****************************************************
 *           decodes pcx files (256 color, as in diablo mpq)
 * Args:
 *     *pFileBuf        the buffer containing the filecontent
 *      uFileSize       the size of the file buffer
 *      uTransColor     the palette entry to be transparent
 *     *uXSize          the actual width is returned herein
 *     *uYSize          the actual height is returned herein
 *
 * Returns: an array containing 4 Bytes (RGBA) for each pixel
 *
 * ---------------------------------------------------------------
 * Comments:    format info and pseudocode taken from:
 *          Klaus Holtorf, "Das Handbuch der Grafikformate"
 *          ISBN 3-7723-6393-8
 ***********************************************************************/
BYTE * WINAPI pcxGetData(BYTE *pFileBuf, DWORD uFileSize, BYTE uTransColor, WORD *uXSize, WORD *uYSize)
{
    uint32_t uFilePos=0;
    uint32_t uDataRead=0;   // potentially big! (logo.pcx: 550 * 216 * 15 = 1,782,000)
    uint16_t i=0;
    uint8_t *data, *palette;
    uint8_t uColorNum=0, uCount=0;
    
    struct pcx_header_t {
        uint8_t     id;
        uint8_t     version;
        uint8_t     compressed;
        uint8_t     bpp;
        uint16_t    x0;
        uint16_t    y0;
        uint16_t    x1;
        uint16_t    y1;
        uint16_t    xdpi;
        uint16_t    ydpi;
        uint8_t     pal[16][3];
        uint8_t     reserved;
        uint8_t     layers;
        uint16_t    rowbytes;
        uint16_t    colortype;
        uint8_t     pad[58];
    } pcxHeader;
    
    if (pFileBuf == NULL) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }
    
    if (uXSize == NULL) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }
        
    if (uYSize == NULL) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }

    // get image information
    memcpy(&pcxHeader, pFileBuf, sizeof(struct pcx_header_t));
    *uXSize = (pcxHeader.x1 - pcxHeader.x0 + 1);
    *uYSize = (pcxHeader.y1 - pcxHeader.y0 + 1);
    
    if ((pcxHeader.version != 2) && (pcxHeader.version != 5)) {
        cerr << "cannot handle pcx v" << pcxHeader.version << "\n";
        return NULL;
    }
    
    // get palette
    palette = new uint8_t[256*4];
    if (pFileBuf[uFileSize - 768 - 1] != 0x0C) {
        cerr << "palette error at " << uFileSize - 768 - 1 << "\n";
        return NULL;
    }
    for (i=0; i<256; i++) {
        memcpy(palette+i*4, pFileBuf+uFileSize-768+i*3, 3*sizeof(uint8_t));
        palette[i*4+3] = 0xFF;
    }
    memset(palette+uTransColor*4, 0, 4*sizeof(uint8_t)); // transparent black
    
    // start right after the header
    uFilePos = sizeof(struct pcx_header_t);
    data = new uint8_t[*uXSize * *uYSize * 4];
    while (uDataRead < (uint32_t)(*uXSize * *uYSize)) {
        // decompress
        uColorNum = pFileBuf[uFilePos++];
        if ((pcxHeader.compressed) && (uColorNum > 0xBF)) {
            uCount = (uColorNum & 0x3F);
            uColorNum = pFileBuf[uFilePos++];
        } else
            uCount = 1;
    
        // draw count pixels with color val
        for (i=0; i<uCount; i++)
            memcpy(data+(uDataRead++)*4, palette+uColorNum*4, 4*sizeof(uint8_t));
    }
    
    // cleanup
    delete[] palette;
    
    return data;
}




See more files for this project here

MaNGOS

MaNGOS is an object-oriented Massively Multiplayer Online Role-Playing Game Server (MMORPGS). It\'s an educational project, to help developers get familar with large scale C++ and C# development projects.

Project homepage: http://sourceforge.net/projects/mangos
Programming language(s): C,C++,SQL
License: gpl2

  bzip2/
    CHANGES
    LICENSE
    Makefile
    Makefile-libbz2_so
    README
    README.COMPILATION.PROBLEMS
    README.XML.STUFF
    Y2K_INFO
    blocksort.c
    bz-common.xsl
    bz-fo.xsl
    bz-html.xsl
    bzdiff
    bzdiff.1
    bzgrep
    bzgrep.1
    bzip.css
    bzip2.1
    bzip2.1.preformatted
    bzip2.c
    bzip2.txt
    bzip2recover.c
    bzlib.c
    bzlib.h
    bzlib_private.h
    bzmore
    bzmore.1
    compress.c
    crctable.c
    decompress.c
    dlltest.c
    dlltest.dsp
    entities.xml
    format.pl
    huffman.c
    libbz2.def
    libbz2.dsp
    makefile.msc
    manual.html
    manual.pdf
    manual.ps
    manual.xml
    mk251.c
    randtable.c
    sample1.bz2
    sample1.ref
    sample2.bz2
    sample2.ref
    sample3.bz2
    sample3.ref
    spewG.c
    unzcrash.c
    words0
    words1
    words2
    words3
    xmlproc.sh
  huffman/
    huff.cpp
    huff.h
  pklib/
    crc32.c
    crc32_pk.c
    explode.c
    implode.c
    pklib.h
  wave/
    wave.cpp
    wave.h
  zlib/
    amiga/
    contrib/
    msdos/
    nt/
    os2/
    ChangeLog
    FAQ
    INDEX
    Makefile
    Makefile.in
    Makefile.riscos
    README
    adler32.c
    algorithm.txt
    compress.c
    configure
    crc32.c
    deflate.c
    deflate.h
    descrip.mms
    example.c
    gzio.c
    infblock.c
    infblock.h
    infcodes.c
    infcodes.h
    inffast.c
    inffast.h
    inffixed.h
    inflate.c
    inftrees.c
    inftrees.h
    infutil.c
    infutil.h
    maketree.c
    minigzip.c
    trees.c
    trees.h
    uncompr.c
    zconf.h
    zlib.3
    zlib.h
    zlib.html
    zmemory.c
    zutil.c
    zutil.h
  GfxDecode.cpp
  Makefile
  SCommon.cpp
  SCommon.h
  SCompression.cpp
  SFileCompactArchive.cpp
  SFileCreateArchiveEx.cpp
  SFileExtractFile.cpp
  SFileFindFile.cpp
  SFileOpenArchive.cpp
  SFileOpenFileEx.cpp
  SFileReadFile.cpp
  SListFile.cpp
  StormDll.h
  StormLib.h
  StormPort.h
  StormPortLinux.cpp
  StormPortMac.cpp