123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 |
- /* Copyright (c) 2002-2012 Croteam Ltd.
- This program is free software; you can redistribute it and/or modify
- it under the terms of version 2 of the GNU General Public License as published by
- the Free Software Foundation
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
- #include "stdh.h"
- #include <Engine/Graphics/ImageInfo.h>
- #include <Engine/Graphics/Color.h>
- #include <Engine/Base/Stream.h>
- #include <Engine/Base/Memory.h>
- #include <Engine/Math/Functions.h>
- extern void FlipBitmap( UBYTE *pubSrc, UBYTE *pubDst, PIX pixWidth, PIX pixHeight, INDEX iFlipType, BOOL bAlphaChannel);
- // Order of CroTeam true color pixel components
- #define COMPONENT_1 red
- #define COMPONENT_2 green
- #define COMPONENT_3 blue
- #define COMPONENT_4 alpha
- // and vice versa
- #define RED_COMPONENT 0
- #define GREEN_COMPONENT 1
- #define BLUE_COMPONENT 2
- #define ALPHA_COMPONENT 3
- // PCX header structure
- struct PCXHeader
- {
- SBYTE MagicID;
- SBYTE Version;
- SBYTE Encoding;
- SBYTE PixelBits;
- SWORD Xmin, Ymin, Xmax, Ymax;
- SWORD Hres, Vres;
- UBYTE Palette[16*3];
- SBYTE Reserved;
- SBYTE Planes;
- UWORD BytesPerLine;
- SWORD PaletteInfo;
- SWORD HscreenSize, VscreenSize;
- SBYTE Filler[54];
- };
- // TARGA header structure
- struct TGAHeader
- {
- UBYTE IdLenght;
- UBYTE ColorMapType;
- UBYTE ImageType;
- UBYTE ColorMapSpec[5];
- UWORD Xorigin;
- UWORD Yorigin;
- UWORD Width;
- UWORD Height;
- UBYTE BitsPerPixel;
- UBYTE Descriptor;
- };
- /******************************************************
- * Routines for manipulating CroTeam picture raw format
- */
- CImageInfo::CImageInfo() {
- Detach();
- }
- CImageInfo::~CImageInfo() {
- Clear();
- }
- // reads image info raw format from file
- void CImageInfo::Read_t( CTStream *inFile) // throw char *
- {
- Clear();
- // read image info header
- inFile->ExpectID_t( CChunkID("CTII"));
- if( inFile->GetSize_t() != 5*4) throw( "Invalid image info file.");
- *inFile >> (PIX)ii_Width;
- *inFile >> (PIX)ii_Height;
- *inFile >> (SLONG)ii_BitsPerPixel;
- // read image contents (all channels)
- ULONG pic_size = ii_Width*ii_Height * ii_BitsPerPixel/8;
- ii_Picture = (UBYTE*)AllocMemory( pic_size);
- inFile->ReadFullChunk_t( CChunkID("IPIC"), ii_Picture, pic_size);
- }
- // writes image info raw format to file
- void CImageInfo::Write_t( CTStream *outFile) const // throw char *
- {
- // write image info header
- outFile->WriteID_t( CChunkID("CTII"));
- outFile->WriteSize_t( 5*4);
- *outFile << (PIX)ii_Width;
- *outFile << (PIX)ii_Height;
- *outFile << (SLONG)ii_BitsPerPixel;
- // write image contents (all channels)
- ULONG pic_size = ii_Width*ii_Height * ii_BitsPerPixel/8;
- outFile->WriteFullChunk_t( CChunkID("IPIC"), ii_Picture, pic_size);
- }
- // initializes structure members and attaches pointer to image
- void CImageInfo::Attach( UBYTE *pPicture, PIX pixWidth, PIX pixHeight, SLONG slBitsPerPixel)
- {
- // parameters must be meaningful
- ASSERT( (pPicture != NULL) && (pixWidth>0) && (pixHeight>0));
- ASSERT( (slBitsPerPixel == 24) || (slBitsPerPixel == 32));
- // do it ...
- ii_Picture = pPicture;
- ii_Width = pixWidth;
- ii_Height = pixHeight;
- ii_BitsPerPixel = slBitsPerPixel;
- }
- // clears the content of an image info structure but does not free allocated memory
- void CImageInfo::Detach(void)
- {
- ii_Picture = NULL;
- ii_Width = 0;
- ii_Height = 0;
- ii_BitsPerPixel = 0;
- }
- // clears the content of an image info structure and frees allocated memory (if any)
- void CImageInfo::Clear()
- {
- // if allocated, release picture memory
- if( ii_Picture != NULL) FreeMemory( ii_Picture);
- Detach();
- }
- // expand image edges
- void CImageInfo::ExpandEdges( INDEX ctPasses/*=8192*/)
- {
- // do nothing if image is too small or doesn't have an alpha channel
- if( ii_Width<3 || ii_Height<3 || ii_BitsPerPixel!=32) return;
- // allocate some memory for spare picture and wipe it clean
- SLONG slSize = ii_Width*ii_Height*ii_BitsPerPixel/8;
- ULONG *pulSrc = (ULONG*)ii_Picture;
- ULONG *pulDst = (ULONG*)AllocMemory(slSize);
- memcpy( pulDst, pulSrc, slSize);
- // loop while there are some more pixels to be processed or for specified number of passes
- for( INDEX iPass=0; iPass<ctPasses; iPass++)
- {
- BOOL bAllPixelsVisible = TRUE;
- // loop thru rows
- for( PIX pixV=1; pixV<ii_Height-1; pixV++)
- { // loop thru pixels in row
- for( PIX pixU=1; pixU<ii_Width-1; pixU++)
- { // determine pixel location
- const PIX pixOffset = pixV*ii_Width + pixU;
- // do nothing if it is already visible
- COLOR col = ByteSwap(pulSrc[pixOffset]);
- if( ((col&CT_AMASK)>>CT_ASHIFT)>3) continue;
- bAllPixelsVisible = FALSE;
- // average all surrounding pixels that are visible
- ULONG ulRa=0, ulGa=0, ulBa=0;
- INDEX ctVisible=0;
- for( INDEX j=-1; j<=1; j++) {
- for( INDEX i=-1; i<=1; i++) {
- const PIX pixSurrOffset = pixOffset + j*ii_Width + i;
- col = ByteSwap(pulSrc[pixSurrOffset]);
- if( ((col&CT_AMASK)>>CT_ASHIFT)<4) continue; // skip non-visible pixels
- UBYTE ubR, ubG, ubB;
- ColorToRGB( col, ubR,ubG,ubB);
- ulRa+=ubR; ulGa+=ubG; ulBa += ubB;
- ctVisible++;
- }
- } // if there were some visible pixels around
- if( ctVisible>0) {
- // calc average
- ulRa/=ctVisible; ulGa/=ctVisible; ulBa/=ctVisible;
- col = RGBAToColor( ulRa,ulGa,ulBa,255);
- // put it to center pixel
- pulDst[pixOffset] = ByteSwap(col);
- }
- }
- } // copy resulting picture over source
- memcpy( pulSrc, pulDst, slSize);
- // done if all pixels are visible
- if( bAllPixelsVisible) break;
- }
- // free temp memory
- FreeMemory(pulDst);
- }
- // sets image info structure members with info form file of any supported graphic format
- // (CT RAW, PCX8, PCX24, TGA32 uncompressed), but does not load picture content nor palette
- INDEX CImageInfo::GetGfxFileInfo_t( const CTFileName &strFileName) // throw char *
- {
- CTFileStream GfxFile;
- TGAHeader TGAhdr;
- PCXHeader PCXhdr;
- // lets assume it's a TGA file
- GfxFile.Open_t( strFileName, CTStream::OM_READ);
- GfxFile.Read_t( &TGAhdr, sizeof( struct TGAHeader));
- GfxFile.Close();
- // check for supported targa format
- if( (TGAhdr.ImageType==2 || TGAhdr.ImageType==10) && TGAhdr.BitsPerPixel>=24) {
- // targa it is, so clear image info and set new values
- Clear();
- ii_Width = TGAhdr.Width;
- ii_Height = TGAhdr.Height;
- ii_BitsPerPixel = TGAhdr.BitsPerPixel;
- // we done here, no need to check further
- return TGA_FILE;
- }
- // we miss Targa, so lets check for supported PCX format
- GfxFile.Open_t( strFileName, CTStream::OM_READ);
- GfxFile.Read_t( &PCXhdr, sizeof( struct PCXHeader));
- GfxFile.Close();
- // check for supported PCX format
- if( (PCXhdr.MagicID == 10) && (PCXhdr.PixelBits == 8)) {
- // PCX it is, so clear image info and set new values
- Clear();
- ii_Width = PCXhdr.Xmax - PCXhdr.Xmin + 1;
- ii_Height = PCXhdr.Ymax - PCXhdr.Ymin + 1;
- ii_BitsPerPixel = PCXhdr.PixelBits * PCXhdr.Planes;
- // we done here, no need to check further
- return PCX_FILE;
- }
- // we didn't found a supported gfx format, sorry ...
- return UNSUPPORTED_FILE;
- }
- /* TGA *********************************************************************************
- * Routines that load and save true color (24 or 32 bit per pixel) uncompressed targa file
- */
- void CImageInfo::LoadTGA_t( const CTFileName &strFileName) // throw char *
- {
- TGAHeader *pTGAHdr;
- UBYTE *pTGABuffer, *pTGAImage;
- SLONG slFileSize;
- CTFileStream TGAFile;
- Clear();
- // determine file size
- TGAFile.Open_t( strFileName, CTStream::OM_READ);
- slFileSize = TGAFile.GetStreamSize();
- // load entire TGA file to memory, as is, and close it (no further usage)
- pTGABuffer = (UBYTE*)AllocMemory( slFileSize);
- TGAFile.Read_t( pTGABuffer, slFileSize);
- TGAFile.Close();
- // TGA header starts at the begining of the TGA file
- pTGAHdr = (struct TGAHeader*)pTGABuffer;
- // TGA image bytes definition follows up
- pTGAImage = pTGABuffer + sizeof(struct TGAHeader) + pTGAHdr->IdLenght;
- // detremine picture size dimensions
- ii_Width = (SLONG)pTGAHdr->Width;
- ii_Height = (SLONG)pTGAHdr->Height;
- ii_BitsPerPixel = (SLONG)pTGAHdr->BitsPerPixel;
- SLONG slBytesPerPixel = ii_BitsPerPixel/8;
- PIX pixBitmapSize = ii_Width*ii_Height;
- BOOL bAlphaChannel = (slBytesPerPixel==4);
- // check for supported file types
- ASSERT( slBytesPerPixel==3 || slBytesPerPixel==4);
- if( slBytesPerPixel!=3 && slBytesPerPixel!=4) throw( TRANS("Unsupported BitsPerPixel in TGA format."));
- // allocate memory for image content
- ii_Picture = (UBYTE*)AllocMemory( ii_Width*ii_Height *slBytesPerPixel);
- UBYTE *pubSrc = pTGAImage; // need 'walking' pointers
- UBYTE *pubDst = ii_Picture;
- // determine TGA image type
- if( pTGAHdr->ImageType==10) {
- // RLE encoded
- UBYTE ubControl;
- INDEX iBlockSize;
- BOOL bRepeat;
- PIX pixCurrentSize=0;
- // loop thru blocks
- while( pixCurrentSize<pixBitmapSize)
- { // readout control byte
- ubControl = *pubSrc++;
- bRepeat = ubControl&0x80;
- iBlockSize = (ubControl&0x7F) +1;
- // repeat or copy color values
- for( INDEX i=0; i<iBlockSize; i++) {
- *pubDst++ = pubSrc[0];
- *pubDst++ = pubSrc[1];
- *pubDst++ = pubSrc[2];
- if( bAlphaChannel) *pubDst++ = pubSrc[3];
- if( !bRepeat) pubSrc += slBytesPerPixel;
- }
- // advance for next block if repeated
- if( bRepeat) pubSrc += slBytesPerPixel;
- // update image size
- pixCurrentSize += iBlockSize;
- }
- // mark that image was encoded to ImageInfo buffer
- pTGAImage = ii_Picture;
- }
- // not true-colored?
- else if( pTGAHdr->ImageType!=2) {
- // whoops!
- ASSERTALWAYS("Unsupported TGA format.");
- throw( TRANS("Unsupported TGA format."));
- }
- // determine image flipping
- INDEX iFlipType;
- switch( (pTGAHdr->Descriptor&0x30)>>4) {
- case 0: iFlipType = 1; break; // vertical flipping
- case 1: iFlipType = 3; break; // diagonal flipping
- case 3: iFlipType = 2; break; // horizontal flipping
- default: iFlipType = 0; break; // no flipping (just copying)
- }
- // do flipping
- FlipBitmap( pTGAImage, ii_Picture, ii_Width, ii_Height, iFlipType, bAlphaChannel);
- // convert TGA pixel format to CroTeam
- pubSrc = ii_Picture; // need 'walking' pointer again
- for( INDEX iPix=0; iPix<pixBitmapSize; iPix++)
- { // flip bytes
- Swap( pubSrc[0], pubSrc[2]); // R & B channels
- pubSrc += slBytesPerPixel;
- }
- // free temorary allocated memory for TGA image format
- FreeMemory( pTGABuffer);
- }
- // save TGA routine
- void CImageInfo::SaveTGA_t( const CTFileName &strFileName) const // throw char *
- {
- TGAHeader *pTGAHdr;
- UBYTE *pTGABuffer, *pTGAImage;
- SLONG slFileSize;
- PIX pixBitmapSize = ii_Width*ii_Height;
- CTFileStream TGAFile;
- // determine and check image info format
- SLONG slBytesPerPixel = ii_BitsPerPixel/8;
- ASSERT( slBytesPerPixel==3 || slBytesPerPixel==4);
- if( slBytesPerPixel!=3 && slBytesPerPixel!=4) throw( TRANS( "Unsupported BitsPerPixel in ImageInfo header."));
- // determine TGA file size and allocate memory
- slFileSize = sizeof(struct TGAHeader) + pixBitmapSize *slBytesPerPixel;
- pTGABuffer = (UBYTE*)AllocMemory( slFileSize);
- pTGAHdr = (struct TGAHeader*)pTGABuffer;
- pTGAImage = pTGABuffer + sizeof(struct TGAHeader);
- // set TGA picture size dimensions
- memset( pTGABuffer, 0x0, sizeof(struct TGAHeader));
- pTGAHdr->Width = (UWORD)ii_Width;
- pTGAHdr->Height = (UWORD)ii_Height;
- pTGAHdr->BitsPerPixel = (UBYTE)ii_BitsPerPixel;
- pTGAHdr->ImageType = 2;
- // flip image vertically
- BOOL bAlphaChannel = (slBytesPerPixel==4);
- FlipBitmap( ii_Picture, pTGAImage, ii_Width, ii_Height, 1, bAlphaChannel);
- // convert CroTeam's pixel format to TGA format
- UBYTE *pubTmp = pTGAImage; // need 'walking' pointer
- for( INDEX iPix=0; iPix<pixBitmapSize; iPix++)
- { // flip bytes
- Swap( pubTmp[0], pubTmp[2]); // R & B channels
- pubTmp += slBytesPerPixel;
- }
- // save entire TGA memory to file and close it
- TGAFile.Create_t( strFileName);
- TGAFile.Write_t( pTGABuffer, slFileSize);
- TGAFile.Close();
- // free temorary allocated memory for TGA image format
- FreeMemory( pTGABuffer);
- }
- /* PCX ***********************************************************************
- * This routine reads file with given file name and if it is valid PCX file it
- * loads it into given ImageInfo structure in CroTeam true-color format.
- * (and, if the one exists, loads the palette)
- */
- void CImageInfo::LoadPCX_t( const CTFileName &strFileName) // throw char *
- {
- PCXHeader *pPCXHdr;
- UBYTE *pPCXBuffer, *pPCXImage, *pPCXDecodedImage, *pTmp;
- UBYTE data, counter;
- SLONG pic_size, PCX_size, slFileSize;
- CTFileStream PCXFile;
- Clear();
- // inconvinent way to determine file size
- PCXFile.Open_t( strFileName, CTStream::OM_READ);
- slFileSize = PCXFile.GetStreamSize();
- // load entire PCX file to memory, as is, and close it (no further usage)
- pPCXBuffer = (UBYTE*)AllocMemory( slFileSize);
- PCXFile.Read_t( pPCXBuffer, slFileSize);
- PCXFile.Close();
- // PCX header starts at the begining of the PCX file
- pPCXHdr = (struct PCXHeader*)pPCXBuffer;
- // PCX image bytes definition follows up
- pPCXImage = pPCXBuffer + sizeof( struct PCXHeader);
- // detremine picture size dimensions
- ii_Width = (SLONG)(pPCXHdr->Xmax - pPCXHdr->Xmin +1);
- ii_Height = (SLONG)(pPCXHdr->Ymax - pPCXHdr->Ymin +1);
- ii_BitsPerPixel = (SLONG)pPCXHdr->Planes*8;
- pic_size = ii_Width * ii_Height * ii_BitsPerPixel/8;
- // allocate memory for image content
- ii_Picture = (UBYTE*)AllocMemory( pic_size);
- // allocate memory for decoded PCX file that hasn't been converted to CT RAW Image format
- PCX_size = (SLONG)(pPCXHdr->BytesPerLine * ii_Height * ii_BitsPerPixel/8);
- pPCXDecodedImage = (UBYTE*)AllocMemory( PCX_size);
- pTmp = pPCXDecodedImage; // save pointer for latter usage
- // decode PCX file
- for( INDEX i=0; i<PCX_size; ) // i is incremented by counter value at the and of the loop
- {
- // read one byte from PCX image in memory
- data = *pPCXImage++;
- // check byte-run mark
- if( (data & 0xC0) == 0xC0) {
- counter = data & 0x3F; // determine repeat value
- data = *pPCXImage++; // read repeated data
- // put several bytes of PCX image to decoded image area in memory
- for( INDEX j=0; j<counter; j++)
- *pPCXDecodedImage++ = data;
- } else {
- // put just one byte from PCX image to decoded image area in memory
- counter = 1;
- *pPCXDecodedImage++ = data;
- }
- // increment encoded image counter
- i += counter;
- }
- pPCXDecodedImage = pTmp; // reset pointer
- // convert decoded PCX image to CroTeam RAW Image Info format
- SLONG slBytesPerPixel = ii_BitsPerPixel/8;
- for( INDEX y=0; y<ii_Height; y++)
- {
- SLONG slYSrcOfs = y * ii_Width * slBytesPerPixel;
- SLONG slYDstOfs = y * pPCXHdr->BytesPerLine * slBytesPerPixel;
- // channel looper
- for( INDEX p=0; p<slBytesPerPixel; p++)
- {
- SLONG slPOffset = p * pPCXHdr->BytesPerLine;
- // byte looper
- for( INDEX x=0; x<ii_Width; x++)
- *(ii_Picture + slYSrcOfs + x*slBytesPerPixel + p) =
- *(pPCXDecodedImage + slYDstOfs + slPOffset + x);
- }
- }
- // free temorary allocated memory for PCX encoded and decoded image
- FreeMemory( pPCXBuffer);
- FreeMemory( pPCXDecodedImage);
- }
- // check for the supported gfx format file and invokes corresponding routine to load it
- void CImageInfo::LoadAnyGfxFormat_t( const CTFileName &strFileName) // throw char *
- {
- INDEX iFileFormat = GetGfxFileInfo_t( strFileName);
- if( iFileFormat == PCX_FILE) LoadPCX_t( strFileName);
- if( iFileFormat == TGA_FILE) LoadTGA_t( strFileName);
- if( iFileFormat == UNSUPPORTED_FILE) throw( "Gfx format not supported.");
- }
|