Blame | Last modification | View Log | RSS feed
// TextureFile.cpp: implementation of the CTextureFile class.////////////////////////////////////////////////////////////////////////#include "TextureFile.h"#include <stdlib.h>#include <stdio.h>//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////CTextureFile::CTextureFile( bool editor ){m_data = NULL;m_numData = 0;m_height = 0;m_width = 0;m_frames.x = 0;m_frames.y = 0;m_frames.rows = 1;m_frames.cols = 1;m_alpha = false;m_alphamap[0] = 0;m_alphamap[1] = 0;m_alphamap[2] = 0;m_animNum = 0;m_anim = NULL;m_collisionMap = false;m_collisionData = NULL;m_numframes = 0;m_framebounds = NULL;m_editor = editor;}CTextureFile::~CTextureFile(){if ( m_data )delete[] m_data;if ( m_collisionData )delete[] m_collisionData;if ( m_anim ){for ( int i = 0; i < m_animNum; i++ ){if ( m_anim[i].frames )delete[] m_anim[i].frames;if ( m_anim[i].name )delete[] m_anim[i].name;}if ( m_editor )free ( m_anim );elsedelete[] m_anim;}//if ( m_framebounds )// delete [] m_framebounds;}STextureData *CTextureFile::CreateData(int width, int height, STextureSize *size ){if ( (!height) || (!width) )return NULL;size->height = height;size->width = width;size->num = (height * width);STextureData *data = new STextureData[size->num];for ( int i = 0; i < size->num; i++ ){data[i].r = 0;data[i].g = 0;data[i].b = 0;data[i].alpha = 255;}return data;}int CTextureFile::LoadTextureTGA(const char *filename ){STextureSize *size = new STextureSize;int error;m_data = LoadTGA ( filename, size, &error );if ( error == TEXTURELOAD_OK ){m_height = size->height;m_width = size->width;m_numData = size->num;}else{delete [] m_data;m_data = NULL;}if ( m_collisionData )delete [] m_collisionData;m_collisionMap = false;delete [] size;return error;}int CTextureFile::LoadCollisionTGA(const char *filename ){STextureSize *size = new STextureSize;int error;STextureData *data = LoadTGA ( filename, size, &error );if ( error == TEXTURELOAD_OK ){if ( (size->height != m_height) || (size->width != m_width) )error = TEXTURELOAD_SIZEMISMATCH;else{if ( m_collisionData )delete [] m_collisionData;m_collisionData = new bool[size->num];for ( int i = 0; i < size->num; i++ )m_collisionData[i] = (data[i].alpha) ? false : true;m_collisionMap = true;}}delete [] data;delete [] size;return error;}bool CTextureFile::SaveTGA ( const char *filename ){FILE *fileID = NULL;unsigned char header[18];unsigned char *imagedata;int i;int num;#ifdef CY_USESECUREif ( fopen_s ( &fileID, filename, "wb" ) )return false;#elsefileID = fopen ( filename, "wb" );if ( !fileID )return false;#endiffor ( i = 0; i < 18; i++ ) //initilise header to all 0'sheader[i] = 0;// setup headerheader[2] = 2;header[12] = m_width % 256;header[13] = (int) (m_width / 256);header[14] = m_height % 256;header[15] = (int) (m_height / 256);header[16] = 32; // 32 bitint bitSize = header[16] / 8;fwrite(header, sizeof (unsigned char), 22, fileID); // write header to the fileimagedata = (unsigned char *)malloc(sizeof(unsigned char) * (m_width * m_height * bitSize));num = 0;// write colour datafor ( i = 0; i < (m_width * m_height); i++){imagedata[num] = m_data[i].b;imagedata[num + 1] = m_data[i].g;imagedata[num + 2] = m_data[i].r;if ( bitSize == 4 )imagedata[num + 3] = (unsigned char) m_data[i].alpha;num += bitSize;}fwrite ( imagedata, sizeof (unsigned char), m_width * m_height * bitSize, fileID );fclose ( fileID );return true;}STextureData *CTextureFile::LoadTGA(const char *filename, STextureSize *tsize, int *error ){unsigned char type[4];unsigned char info[7];unsigned char *imageData = NULL;int imageWidth, imageHeight;int imageBits, size;FILE *fileID;// open the filename#ifdef CY_USESECUREif ( fopen_s ( &fileID, filename, "r+bt") ){*error = TEXTURELOAD_NOFILE;return NULL;}#elseif (!(fileID = fopen (filename, "r+bt"))){*error = TEXTURELOAD_NOFILE;return NULL;}#endif// get the heading datafread (&type, sizeof (char), 3, fileID); // read in colormap info and image typefseek (fileID, 12, SEEK_SET); // seek past the headerfread (&info, sizeof (char), 6, fileID);/*if (type[1] != 0 || (type[2] != 2 && type[2] != 3)){fclose ( fileID );return false;}*/// convert heading to dataimageWidth = info[0] + info[1] * 256; // get image size from the headerimageHeight = info[2] + info[3] * 256;imageBits = info[4];size = imageWidth * imageHeight; // number of bits in image file// check for right format to loadif ( (imageBits != 32) && (imageBits != 24) ) // invalid format{*error = TEXTURELOAD_INVALIDFORMAT;fclose ( fileID );return false;}/* if ( imageBits != 32 ){fclose ( fileID );*error = TEXTURELOAD_INVALIDFORMAT;return NULL;}*/int bitSize = (imageBits / 8);// read the dataimageData = (unsigned char *)malloc (size * bitSize);if (imageData == NULL){fclose ( fileID );*error = TEXTURELOAD_INVALIDFORMAT;return NULL;}if ( (int)fread (imageData, sizeof (unsigned char), size * bitSize, fileID) != (int)(size * bitSize) ){free (imageData);*error = TEXTURELOAD_INVALIDFORMAT;return NULL;}// dont use greyscale ?// create the data storageSTextureData *data = CreateData ( imageWidth, imageHeight, tsize );if ( !data ){free (imageData);*error = TEXTURELOAD_INVALIDFORMAT;return NULL;}// copy to data storageint tempI;for ( int i = 0; i < size; i++ ){tempI = i * bitSize;data[i].b = imageData[tempI];data[i].g = imageData[tempI + 1];data[i].r = imageData[tempI + 2];if ( imageBits == 32 )data[i].alpha = imageData[tempI + 3];}free ( imageData );fclose (fileID);*error = TEXTURELOAD_OK;return data;}#ifdef DIRECT3DLPDIRECT3DTEXTURE9 CTextureFile::CreateTexture(LPDIRECT3DDEVICE9 device){if ( m_numData < 1 )return NULL;LPDIRECT3DTEXTURE9 texture;if ( FAILED (D3DXCreateTexture ( device, m_width, m_height, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &texture )) )return NULL;D3DSURFACE_DESC surfDesc;texture->GetLevelDesc( 0, &surfDesc );int h = surfDesc.Height;D3DLOCKED_RECT LockedRect;texture->LockRect( 0, &LockedRect, NULL, 0 );DWORD* pBits;for( DWORD iTexelZ=0; iTexelZ < surfDesc.Height; iTexelZ++ ){pBits = (DWORD*) ((BYTE*)LockedRect.pBits + (LockedRect.Pitch * iTexelZ));for( DWORD iTexelX = 0; iTexelX < surfDesc.Width; iTexelX++ ){int num = m_numData - ((iTexelZ * surfDesc.Width) + (surfDesc.Width - iTexelX));DWORD nRed = (DWORD) m_data[num].r;DWORD nGreen = (DWORD) m_data[num].g;DWORD nBlue = (DWORD) m_data[num].b;DWORD nAlpha = (DWORD) m_data[num].alpha;if ( m_alpha ){if ( (m_data[num].r == m_alphamap[0]) && (m_data[num].g == m_alphamap[1]) && (m_data[num].b == m_alphamap[2]) )nAlpha = 0;}if( nRed > 0xFF )nRed = 0xFF;if( nGreen > 0xFF )nGreen = 0xFF;if( nBlue > 0xFF )nBlue = 0xFF;if( nAlpha > 0xFF )nAlpha = 0xFF;*pBits = (nAlpha << 24) + (nRed << 16) + (nGreen << 8) + (nBlue << 0);pBits++;}}texture->UnlockRect ( 0 );return texture;}LPDIRECT3DTEXTURE9 CTextureFile::CreateCollisionTexture(LPDIRECT3DDEVICE9 device, DWORD nRed, DWORD nGreen, DWORD nBlue){if ( (m_numData < 1) || (!m_collisionMap) || (!m_collisionData) )return NULL;LPDIRECT3DTEXTURE9 texture;if ( FAILED (D3DXCreateTexture ( device, m_width, m_height, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &texture )) )return NULL;D3DSURFACE_DESC surfDesc;texture->GetLevelDesc( 0, &surfDesc );int h = surfDesc.Height;D3DLOCKED_RECT LockedRect;texture->LockRect( 0, &LockedRect, NULL, 0 );DWORD* pBits;for( DWORD iTexelZ=0; iTexelZ < surfDesc.Height; iTexelZ++ ){pBits = (DWORD*) ((BYTE*)LockedRect.pBits + (LockedRect.Pitch * iTexelZ));for( DWORD iTexelX = 0; iTexelX < surfDesc.Width; iTexelX++ ){int num = m_numData - ((iTexelZ * surfDesc.Width) + (surfDesc.Width - iTexelX));DWORD nAlpha = 0xFF;if ( m_collisionData[num] )nAlpha = 0x00;if( nRed > 0xFF )nRed = 0xFF;if( nGreen > 0xFF )nGreen = 0xFF;if( nBlue > 0xFF )nBlue = 0xFF;if( nAlpha > 0xFF )nAlpha = 0xFF;*pBits = (nAlpha << 24) + (nRed << 16) + (nGreen << 8) + (nBlue << 0);pBits++;}}texture->UnlockRect ( 0 );return texture;}#endifbool CTextureFile::Save(const char *filename){// create headerSFileHeader header;ClearHeader ( &header );// open fileFILE *id;#ifdef CY_USESECUREif ( fopen_s ( &id, filename, "wb" ) )return false;#elseif ( (id = fopen ( filename, "wb" )) == NULL )return false;#endif// write version numbers (used incase header needs to change in later versions)float version = (float) TEXTUREFILE_VERSION;fwrite ( &version, sizeof ( float ), 1, id );// write header to fileheader.width = m_width;header.height = m_height;header.frames = false;header.alpha = m_alpha;header.alphamap[0] = m_alphamap[0];header.alphamap[1] = m_alphamap[1];header.alphamap[2] = m_alphamap[2];if ( m_animNum )header.frames = true;fwrite ( &header, sizeof ( SFileHeader ), 1, id );// * Added since verison 1.20fwrite ( &m_collisionMap, sizeof ( bool ), 1, id );// write all the datafwrite ( m_data, sizeof ( STextureData ), m_numData, id );// write frames datafwrite ( &m_frames, sizeof ( STextureFrames ), 1, id );int animNum = 0;int i;for ( i = 0; i < m_animNum; i++ ){if ( !m_anim[i].remove )animNum++;}fwrite ( &animNum, sizeof ( int ), 1, id );SAnimation *anim;for ( i = 0; i < m_animNum; i++ ){anim = &m_anim[i];if ( !anim->remove ){int size = (int)strlen ( anim->name ) + 1;fwrite ( &size, sizeof ( int ), 1, id );fwrite ( anim->name, sizeof ( char ), size, id );fwrite ( &anim->amt, sizeof ( int ), 1, id );fwrite ( &anim->delay, sizeof ( int ), 1, id );fwrite ( &anim->cont, sizeof ( bool ), 1, id );fwrite ( anim->frames, sizeof ( int ), anim->amt, id );}}if ( m_collisionMap )fwrite ( m_collisionData, sizeof ( bool ), m_numData, id );fclose ( id );return true;}void CTextureFile::ClearHeader(SFileHeader *header){header->alpha = false;header->alphamap[0] = 0;header->alphamap[1] = 0;header->alphamap[2] = 0;header->frames = false;header->height = 0;header->width = 0;}bool CTextureFile::Load(const char *filename){// create headerSFileHeader header;ClearHeader ( &header );// open fileFILE *id;#ifdef CY_USESECUREif ( fopen_s ( &id, filename, "rb" ) )return false;#elseif ( (id = fopen ( filename, "rb" )) == NULL )return false;#endif// read version numbers (used incase header needs to change in later versions)float version;fread ( &version, sizeof ( float ), 1, id );if ( version < 1.00 )return false;// read header from filefread ( &header, sizeof ( SFileHeader ), 1, id );m_width = header.width;m_height = header.height;m_numData = m_width * m_height;m_alpha = header.alpha;m_alphamap[0] = header.alphamap[0];m_alphamap[1] = header.alphamap[1];m_alphamap[2] = header.alphamap[2];m_alpha = header.alpha;// * Added since version 1.20if ( version > 1.20 )fread ( &m_collisionMap, sizeof ( bool ), 1, id );// read all the datam_data = new STextureData[m_numData];if ( fread ( m_data, sizeof ( STextureData ), m_numData, id ) != m_numData )return false;fread ( &m_frames, sizeof ( STextureFrames ), 1, id );if ( (version >= 1.1) && (header.frames) ){// read number of animationsint fnum, size;fread ( &fnum, sizeof ( int ), 1, id );if ( m_anim ){if ( m_editor )free ( m_anim );elsedelete []m_anim;}if ( !fnum )m_anim = NULL;else{if ( m_editor )m_anim = (SAnimation *)malloc(sizeof ( SAnimation ) * fnum);elsem_anim = new SAnimation[fnum];}SAnimation *anim;for ( int i = 0; i < fnum; i++ ){anim = &m_anim[i];fread ( &size, sizeof ( int ), 1, id );anim->name = new char[size];fread ( anim->name, sizeof ( char ), size, id );fread ( &anim->amt, sizeof ( int ), 1, id );fread ( &anim->delay, sizeof ( int ), 1, id );fread ( &anim->cont, sizeof ( bool ), 1, id );anim->remove = false;anim->frames = new int[anim->amt];fread ( anim->frames, sizeof ( int ), anim->amt, id );}m_animNum = fnum;}if ( m_collisionMap ){m_collisionData = new bool[m_numData];if ( fread ( m_collisionData, sizeof ( bool ), m_numData, id ) != m_numData )return false;}fclose ( id );m_numframes = m_frames.x * m_frames.y;m_framebounds = new SFrameBounds[m_numframes];for ( int i = 0; i < m_numframes; i++ ){m_framebounds[i].minx = ComputeMinAlphaX ( i );m_framebounds[i].maxx = ComputeMaxAlphaX ( i );m_framebounds[i].miny = ComputeMinAlphaY ( i );m_framebounds[i].maxy = ComputeMaxAlphaY ( i );}return true;}void CTextureFile::SetFrameSize(int width, int height){m_frames.x = width;m_frames.y = height;}const STextureFrames *CTextureFile::GetFrames(){return &m_frames;}int CTextureFile::GetFrameWidth(){return m_frames.x;}int CTextureFile::GetFrameHeight(){return m_frames.y;}void CTextureFile::SetFrames(int rows, int cols){m_frames.rows = rows;m_frames.cols = cols;}void CTextureFile::EnableAlphamap(bool enable){m_alpha = enable;}bool CTextureFile::GetAlphaMap(){return m_alpha;}void CTextureFile::SetAlphaMap(int red, int green, int blue){m_alphamap[0] = red;m_alphamap[1] = green;m_alphamap[2] = blue;}bool CTextureFile::GetAlphaMap(int *red, int *green, int *blue){*red = m_alphamap[0];*green = m_alphamap[1];*blue = m_alphamap[2];return m_alpha;}SAnimation * CTextureFile::AddNewAnimation(const char *name){SAnimation *anim = NULL;// first, find if theres any free slotsfor ( int i = 0; i < m_animNum; i++ ){// found a free slotif ( m_anim[i].remove ){anim = &m_anim[i];// make sure old data is cleared before usingif ( anim->frames )delete []anim->frames;if ( anim->name )delete []anim->name;break;}}// no free slot ? add a new one to the end of the arrayif ( !anim ){++m_animNum;m_anim = (SAnimation *)realloc(m_anim, sizeof ( SAnimation ) * m_animNum);anim = &m_anim[m_animNum - 1];}// set default data for animationanim->amt = 1;anim->frames = new int[1];anim->remove = false;anim->frames[0] = 1;anim->cont = false;anim->delay = 1;anim->name = new char[strlen (name) + 1];#ifdef CY_USESECUREstrcpy_s ( anim->name, strlen (name) + 1, name );#elsestrcpy ( anim->name, name );#endif// return pointer to created animationreturn anim;}int CTextureFile::GetAnimationNum(){return m_animNum;}SAnimation * CTextureFile::FindAnimation(const char *search){Utils::String sSearch(search);for ( int i = 0; i < m_animNum; i++ ) {if ( !m_anim[i].remove ) {if ( sSearch.Compare(m_anim[i].name) ) {return &m_anim[i];}}}return NULL;}SAnimation * CTextureFile::GetAnimation(int num){if ( (m_animNum < num) || (num < 0) )return NULL;return &m_anim[num];}void CTextureFile::SetEditor(){m_editor = true;}void IncAnimationFrame ( SPlayAnimation *anim, int *times ){IncAnimationFrame ( anim, false, times );}void IncAnimationFrame ( SPlayAnimation *anim, bool endstop, int *times ){if ( !anim )return;if ( !anim->anim )return;++anim->delay;if ( anim->delay >= anim->anim->delay ){anim->delay = 0;++anim->curframe;if ( anim->curframe > anim->anim->amt ){if ( anim->anim->cont ){anim->curframe = 1;if ( times )++(*times);}else if ( endstop )--anim->curframe;elseanim->anim = NULL;}}}void DecAnimationFrame ( SPlayAnimation *anim, int *times ){DecAnimationFrame ( anim, false, times );}void DecAnimationFrame ( SPlayAnimation *anim, bool endstop, int *times ){if ( !anim )return;if ( !anim->anim )return;++anim->delay;if ( anim->delay >= anim->anim->delay ){anim->delay = 0;--anim->curframe;if ( anim->curframe < 1 ){if ( anim->anim->cont ){anim->curframe = anim->anim->amt;if ( times )++(*times);}else if ( endstop )anim->curframe = 1;elseanim->anim = NULL;}}}void ResetAnimation ( SPlayAnimation *anim ){if ( !anim )return;anim->anim = NULL;anim->delay = 0;anim->curframe = 1;anim->reverse = false;}void DoAnimation ( SPlayAnimation *anim, bool endstopinc, bool endstopdec, int *times ){if ( !anim )return;if ( anim->reverse )DecAnimationFrame ( anim, endstopdec, times );elseIncAnimationFrame ( anim, endstopinc, times );}bool CTextureFile::CheckAlpha(int x, int y, int frame, bool inccollisionmap){int row = ((frame - 1) / m_frames.cols) + 1;int col = frame % m_frames.cols;if ( col == 0)col = m_frames.cols;int newx = ((col - 1) * m_frames.x) + x;int newy = ((row - 1) * m_frames.y) + y;int num = (newy * m_width) + newx;if ( (num < 0) || (num > (m_width * m_height)) )return false;if ( (inccollisionmap) && (m_collisionMap) && (m_collisionData) )return m_collisionData[num];int r = m_data[num].r;int g = m_data[num].g;int b = m_data[num].b;int a = m_data[num].alpha;if ( m_data[num].alpha == 0 )return true;if ( m_alpha ){if ( (m_data[num].r == m_alphamap[0]) && (m_data[num].g == m_alphamap[1]) && (m_data[num].b == m_alphamap[2]) )return true;}return false;}std::string CTextureFile::GetErrorText ( int error ){switch ( error ){case TEXTURELOAD_OK:return "";case TEXTURELOAD_NOFILE:return "unable to open file";case TEXTURELOAD_SIZEMISMATCH:return "size mismatch";case TEXTURELOAD_INVALIDFORMAT:return "Invalid Format";}return "Unknown Error";}int CTextureFile::ComputeMinAlphaX ( int frame ){for ( unsigned int x = 0; x < m_frames.x; x++ ){for ( unsigned int y = 0; y < m_frames.y; y++ ){if ( !CheckAlpha ( x, y, frame ) )return x;}}return 0;}int CTextureFile::ComputeMaxAlphaX ( int frame ){for ( unsigned int x = m_frames.x - 1; x >= 0; x-- ){for ( unsigned int y = 0; y < m_frames.y; y++ ){if ( !CheckAlpha ( x, y, frame ) )return x;}}return m_frames.x - 1;}int CTextureFile::ComputeMinAlphaY ( int frame ){for ( unsigned int y = 0; y < m_frames.y; y++ ){for ( unsigned int x = 0; x < m_frames.x; x++ ){if ( !CheckAlpha ( x, y, frame ) )return y;}}return 0;}int CTextureFile::ComputeMaxAlphaY ( int frame ){for ( unsigned int y = m_frames.y - 1; y >= 0; y-- ){for ( unsigned int x = 0; x < m_frames.x; x++ ){if ( !CheckAlpha ( x, y, frame ) )return y;}}return m_frames.y - 1;}