 /* 'mrRGBAImage.cpp' */

 /* Komplementarny plik nagłówka */
#include "mrRGBAImage.h"

 /* Konstruktor domyślny */
mrRGBAImage::mrRGBAImage (void)
{
 m_iWidth        = 0;
 m_iHeight       = 0;
 m_piImageBuffer = NULL;
}

 /* Destruktor domyślny */
mrRGBAImage::~mrRGBAImage (void)
{
 m_iWidth        = 0;
 m_iHeight       = 0;

  /* Jeżeli zarezerwowana była pamięć uwolnij ją */
 if (NULL != m_piImageBuffer)
 {
  delete [] m_piImageBuffer;
  m_piImageBuffer = NULL;
 }
}

 /* Skopiuj ten obraz do innego */
mrRGBAImage & mrRGBAImage::operator = (mrRGBAImage & rkImage)
{
 m_iWidth  = rkImage.GetWidth ();
 m_iHeight = rkImage.GetHeight ();
 SetImageBuffer (rkImage.GetImageBuffer ());

  /* Zwraca egzemplarz tej klasy */
 return * this;
}

 /* Załaduj obraz z pliku mapy bitowej Windows */
mrError32 mrRGBAImage::LoadFromBitmap (LPSTR lpszFilename)
{
 fstream      kBitmap;

 kBitmap.open (lpszFilename, ios::binary | ios::in);

 if (kBitmap.is_open ())
 {
  mrUInt16     iType;
  kBitmap.read ((char *) &iType, sizeof (mrUInt16));

   /* Pobierz sygnaturę mapy bitowej */
  if (0x4D42 != iType)
  {
   return mrErrorNotBitmapFile;
  }

   /* Zignoruj osiem bajtów */
  kBitmap.seekg (8, ios::cur);

   /* Pobierz pozycję początku bufora mapy bitowej */
  mrUInt32     iStartBuffer;
  kBitmap.read ((char *) &iStartBuffer, sizeof (mrUInt32));

   /* Zignoruj cztery bajty */
  kBitmap.seekg (4, ios::cur);

   /* Pobierz szerokość i wysokość mapy bitowej */
  kBitmap.read ((char *) &m_iWidth, sizeof (mrUInt32));
  kBitmap.read ((char *) &m_iHeight, sizeof (mrUInt32));
 
   /* Zignoruj dwa bajty */
  kBitmap.seekg (2, ios::cur);

   /* Pobierz liczbę bitów */
  mrUInt16     iBitCount;
  kBitmap.read ((char *) &iBitCount, sizeof (mrUInt16));

   /* Jeżeli nie jest to tryb 24-bitowy, zwraca błąd */
  if (iBitCount != 24)
  {
   return mrErrorBitmapNotSupported;
  }
   /* Pobierz kompresję */
  mrUInt32     iCompression;
  kBitmap.read ((char *) &iCompression, sizeof (mrUInt32));

   /* Jeżeli plik jest skompresowany, nie zostanie obsłużony. Zwraca błąd  */
  if (iCompression != BI_RGB)
  {
   return mrErrorBitmapNotSupported;
  }
 
   /* Przejdź do bufora mapy bitowej */
  kBitmap.seekg (iStartBuffer, ios::beg);

   /* Odczytaj bufor obrazu z pliku */
  mrUInt8 * piBuffer = new mrUInt8 [m_iWidth * m_iHeight * 3];
  kBitmap.read ((char *) piBuffer, m_iWidth * m_iHeight * 3 * 
                sizeof (mrUInt8));

   /* Zarezerwuj pamięć dla bufora */
  if (NULL != m_piImageBuffer)
  {
   delete [] m_piImageBuffer;
  }
  m_piImageBuffer = new mrUInt32 [m_iWidth * m_iHeight];

   /* Pobierz komponenty koloru każdego z pikseli i wypełnij bufor obrazu */ 
  mrUInt32 iX, iY;

  for (iY = 0; iY < m_iHeight; iY++)
  {
   for (iX = 0; iX < m_iWidth; iX++)
   {
     /* Obraz wymaga odwrócenia */
    if (m_iHeight > 0)
    {
      m_piImageBuffer [iX + (m_iHeight - 1 - iY) * (m_iWidth)] = 255 |
            (piBuffer [(iX + iY * (m_iWidth)) * 3 + 0] << 8) |
            (piBuffer [(iX + iY * (m_iWidth)) * 3 + 1] << 16) |
            (piBuffer [(iX + iY * (m_iWidth)) * 3 + 2] << 24);
    }
     /* Obraz nie musi być odwrócony */
    else
    {
     m_piImageBuffer [iX + (iY * m_iWidth)] =  255 |
            (piBuffer [iX + (iY * m_iWidth) * 3 + 0] << 8) |
            (piBuffer [iX + (iY * m_iWidth) * 3 + 1] << 16) |
            (piBuffer [iX + (iY * m_iWidth) * 3 + 2] << 24);
    }
   }
  }

   /* Zamknij plik, zwolnij pamięć i zwróć brak błędu */
  if (NULL != piBuffer)
  {
   delete [] piBuffer;
  }

  kBitmap.close ();
 }

 return mrNoError;
}

 /* Załaduj obraz z pliku TARGA */
mrError32 mrRGBAImage::LoadFromTarga (LPSTR lpszFilename)
{
 fstream      kTarga;

 kTarga.open (lpszFilename, ios::binary | ios::in);
 
 if (kTarga.is_open ())
 {
   /* Odczytaj rozmiar opisu pól */
  mrUInt8      iFieldDescSize;
  kTarga.read ((char *) &iFieldDescSize, sizeof (mrUInt8));

   /* Zignoruj jeden bajt */
  kTarga.seekg (1, ios::cur);

   /* Odczytaj kod koloru obrazu */
  mrUInt8      iImageCode;
  kTarga.read ((char *) &iImageCode, sizeof (mrUInt8));

  if (2 != iImageCode)
  {
   return mrErrorTargaNotSupported;
  }

   /* Zignoruj dwa bajty */
  kTarga.seekg (2, ios::cur);

   /* Odczytaj mapę kolorów */
  mrUInt16      iMapLength;
  kTarga.read ((char *) &iMapLength, sizeof (mrUInt16));

   /* Zignoruj jeden bajt */
  kTarga.seekg (1, ios::cur);

   /* Odczytaj początkową pozycję obrazu */
  mrUInt16      iXStart;
  kTarga.read ((char *) &iXStart, sizeof (mrUInt16));
  mrUInt16      iYStart;
  kTarga.read ((char *) &iYStart, sizeof (mrUInt16));

   /* Odczytaj rozmiar obrazu */
  mrUInt16      iWidth;
  kTarga.read ((char *) &iWidth, sizeof (mrUInt16));
  mrUInt16      iHeight;
  kTarga.read ((char *) &iHeight, sizeof (mrUInt16));

  m_iWidth  = iWidth;
  m_iHeight = iHeight;

   /* Odczytaj głębię kolorów obrazu */
  mrUInt8      iImageBits;

  kTarga.read ((char *) &iImageBits, sizeof (mrUInt8));
  if (32 != iImageBits)
  {
   return mrErrorTargaNotSupported;
  }

   /* Odczytaj opis obrazu */
  mrUInt8      iImageDesc;
  kTarga.read ((char *) &iImageDesc, sizeof (mrUInt8));
 
   /* Zignoruj opis pól */
  kTarga.seekg (iFieldDescSize, ios::cur);
   /* Zignoruj mapę kolorów */
  kTarga.seekg (iMapLength * 4, ios::cur);
 
   /* Odczytaj bufor obrazu z pliku */
  mrUInt32 * piBuffer = new mrUInt32 [m_iWidth * m_iHeight];
  kTarga.read ((char *) piBuffer, m_iWidth * m_iHeight * 4 * 
                sizeof (mrUInt8));

   /* Zarezerwuj pamięć dla bufora obrazu */
  if (NULL != m_piImageBuffer)
  {
   delete [] m_piImageBuffer;
  }
  m_piImageBuffer = new mrUInt32 [m_iWidth * m_iHeight];

  mrUInt8  iRed, iGreen, iBlue, iAlpha;
  mrUInt32 iColor;

   /* Pobierz komponenty koloru każdego piksela i wypełnij bufor obrazu */ 
  mrUInt32 iX, iY;

  for (iY = 0; iY < m_iHeight; iY++)
  {
   for (iX = 0; iX < m_iWidth; iX++)
   {
     /* Obraz nie musi być odwrócony */
    if ((iImageDesc & 1) << 4)
    {
      /* Pobierz komponenty koloru */
     iColor = piBuffer [iX + (iY * m_iWidth)];

     iAlpha = (mrUInt8)((iColor & 0xFF000000) >> 24);
     iRed   = (mrUInt8)((iColor & 0x00FF0000) >> 16);
     iGreen = (mrUInt8)((iColor & 0x0000FF00) >> 8);
     iBlue  = (mrUInt8)((iColor & 0x000000FF));

      /* Skopiuj odwróconą pozycję */
     m_piImageBuffer [iX + (iY * m_iWidth)] = 
            iAlpha << 0 | iBlue << 8 | iGreen << 16 | iRed << 24;
    }
     /* Musi być odwrócony */
    else
    {
      /* Pobierz komponenty koloru */
     iColor = piBuffer [iX + (iY * m_iWidth)];

     iAlpha = (mrUInt8)((iColor & 0xFF000000) >> 24);
     iRed   = (mrUInt8)((iColor & 0x00FF0000) >> 16);
     iGreen = (mrUInt8)((iColor & 0x0000FF00) >> 8);
     iBlue  = (mrUInt8)((iColor & 0x000000FF));

      /* Skopiuj pozycję */
     m_piImageBuffer [iX + (m_iHeight - 1 - iY) * (m_iWidth)] = 
            iAlpha << 0 | iBlue << 8 | iGreen << 16 | iRed << 24;
    }
   }
  }

   /* Zamknij plik, uwolnij pamięć i zwróć brak błędu */
  if (NULL != piBuffer)
  {
   delete [] piBuffer;
  }

  kTarga.close ();
  }

 return mrNoError;

}


 /* Ustaw klucz koloru obrazu dla renderowania */
void mrRGBAImage::SetColorKey (mrUInt8 iRed, mrUInt8 iGreen, 
                               mrUInt8 iBlue)
{
  /* Pobierz komponenty koloru każdego piksela i ustaw klucz koloru */ 
 mrUInt32 iX, iY;
 mrUInt8 iOriRed, iOriGreen, iOriBlue;

 for (iY = 0; iY < m_iHeight; iY++)
 {
  for (iX = 0; iX < m_iWidth; iX++)
  {
   iOriRed   = (mrUInt8)((m_piImageBuffer [iX + (iY * m_iWidth)] 
                         & 0xFF000000) >> 24);
   iOriGreen = (mrUInt8)((m_piImageBuffer [iX + (iY * m_iWidth)] 
                         & 0x00FF0000) >> 16);
   iOriBlue  = (mrUInt8)((m_piImageBuffer [iX + (iY * m_iWidth)] 
                         & 0x0000FF00) >> 8);

    /* Jeżeli kolor się zgadza, ustaw alfa na zero */
   if ( (iOriRed == iRed) && (iOriGreen == iGreen) && (iOriBlue == iBlue))
   {
    m_piImageBuffer [iX + (iY * m_iWidth)] = iOriRed   << 24 | 
                                             iOriGreen << 16 | 
                                             iOriBlue  << 8  | 
                                             0;
   }
  }
 }
}

 /* Ustaw szerokość obrazu */
void mrRGBAImage::SetWidth (mrUInt32 iWidth)
{
 m_iWidth = iWidth;
}

 /* Ustaw wysokość obrazu */
void mrRGBAImage::SetHeight (mrUInt32 iHeight)
{
 m_iHeight = iHeight;
}

 /* Ustaw kolor w danej pozycji */
void mrRGBAImage::SetColor (mrUInt32 iX, mrUInt32 iY, mrUInt8 iRed, 
                            mrUInt8 iGreen, mrUInt8 iBlue, 
                            mrUInt8 iAlpha)
{
 mrUInt32 iColor;
 iColor = D3DCOLOR_RGBA (iRed, iGreen, iBlue, iAlpha);

 m_piImageBuffer [iX + (iY * m_iWidth - 1)] = iColor;
}

 /* Ustaw bufor obrazu */
void mrRGBAImage::SetImageBuffer (mrUInt32 * pImage)
{
 if (NULL != m_piImageBuffer)
 {
  delete [] m_piImageBuffer;
 }
 m_piImageBuffer = new mrUInt32 [m_iWidth * m_iHeight];

 memcpy (m_piImageBuffer, pImage, 
         sizeof (mrUInt32) * m_iWidth * m_iHeight);
}

 /* Zwraca szerokość obrazu */
mrUInt32 mrRGBAImage::GetWidth (void)
{
 return m_iWidth;
}

 /* Zwraca wysokość obrazu */
mrUInt32 mrRGBAImage::GetHeight (void)
{
 return m_iHeight;
}

 /* Zwraca kolor obrazu w danym punkcie */
mrUInt32 mrRGBAImage::GetColor (mrUInt32 iX, mrUInt32 iY)
{
 return m_piImageBuffer [iX + iY * m_iWidth];
}

 /* Zwraca bufor obrazu */
mrUInt32 * mrRGBAImage::GetImageBuffer (void)
{
 return m_piImageBuffer;
}
