/***************************************************************************
 *   Copyright (C) 2007 by A.J. Tavakoli                                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>

#include "TGAFile.h"


TGAFile::TGAFile():
     width(0),
     height(0),
     bpp(0),
     data(NULL) {

}


TGAFile::TGAFile(const TGAFile &tga) {
  width = height = 0;
  bpp = 0;
  data = NULL;

  if ( tga.getWidth()  <= 0  ||
       tga.getHeight() <= 0 ||
       tga.getData() == NULL )    
    return;

  int sz = tga.getWidth()*tga.getHeight()*(tga.getBPP() >> 3);
  data = new unsigned char[sz];

  if ( NULL == data )
    return;

  memcpy(data, tga.getData(), size_t(sz));

  width = tga.getWidth();
  height = tga.getHeight();
  bpp = tga.getBPP();  
}


TGAFile::~TGAFile() {
  clear();
}


// clears any loaded image data
void TGAFile::clear() {
  if ( data != NULL ) {
    delete [] data;
    data = NULL;
  }

  width = height = bpp = 0;
}


// loads data from tga file on disk
// (only uncompressed 24-bit or 32-bit tga files supported)
bool TGAFile::load(const char *filename) {
  // attempt to open file for reading
  FILE *fin = fopen(filename, "rb");

  // was open successful?
  if ( NULL == fin )
    return false;

  // read in 18 byte header
  unsigned char header[18];
  if ( fread(header, 1, 18, fin) != 18 ) {
    // reached EOF before could finish reading header
    fclose(fin);
    return false;
  }

  // make sure this is an uncompressed 24-bit or 32-bit TGA file
  // (3rd byte must be 2, with the rest of the first 12 bytes being 0's)
  for ( int i=0; i < 12; i++ ) {
    if ( (i != 2 && header[i] != 0) ||
         (2 == i && header[i] != 2) ) {
      fclose(fin);
      return false;
    }
  }

  // extract width, height, and color depth from 
  // convert bytes to ints
  int w = 0, h = 0, _bpp = int(header[16]);

  w = (int(header[13])  << 8) + int(header[12]);
  h = (int(header[15]) << 8) + int(header[14]);

  // confirm that this is a 24 or 32-bit image
  if ( _bpp != 24 && _bpp != 32 ) {
    fclose(fin);
    return false;
  }

  // allocate storage for image
  size_t sz = size_t( w*h*(_bpp >> 3) );
  unsigned char *imageData = new unsigned char[sz];

  if ( NULL == imageData ) {
    fclose(fin);
    return false;
  }

  // finally, read in the image
  size_t bytesRead = fread(imageData, 1, sz, fin);
  fclose(fin);

  if ( bytesRead < sz ) {
    delete [] imageData;
    return false;
  }

  // data in TGA is stored as BGR, so iterate through the image and swap
  // B and R to make it RGB
  size_t bytesPerPxl = size_t(_bpp >> 3);
  for ( size_t i=0; i < sz; i+=bytesPerPxl ) {
    unsigned char tmp = imageData[i];
    imageData[i] = imageData[i+2];
    imageData[i+2] = tmp;
  }

  width  = w;
  height = h;
  bpp = _bpp;
  data = imageData;

  // indicate success
  return true;
}

