⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gfxdecode.cpp

📁 絲路server源碼 Silk Road server source
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    
    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;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -