// may be #define True3Color
// may be #define USE_SMX_API
//#define USE_SMX_API
//---------------------------------------------------------------------------

#include "LoadBMP.h"

#ifdef USE_SMX_API

//#include <std.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#include "SMX_API.h"
#define BMP_fopen(lpFileName)            sfs_fopen(lpFileName, "r")
#define BMP_fread(ptr, n, stream)        sfs_fread(ptr, 1, n, stream)
#define BMP_fclose(stream)               if (stream) sfs_fclose(stream); stream=0;
#define BMP_FILE                         FILESTRUCT
#else
#include <stdio.h>
#define BMP_fopen(lpFileName)            fopen(lpFileName,	"rb")
#define BMP_fread(ptr, n, stream)        fread(ptr, 1, n, stream)
#define BMP_fclose(stream)               if (stream) fclose(stream); stream=0;
#define BMP_FILE                         FILE
#endif

//---------------------------------------------------------------------------

int  LoadBMP (          char*  lpFileName ,
               unsigned char** A      ,
               int           & He     ,
               int           & Wi     )
//----------------------------
{

   BMP_FILE *F=0;
   static unsigned char Buff[2048];
   unsigned int iBuff=0,iPos=0,ii;

   unsigned char A1,A2,A3,A4;
   unsigned char AA;
   unsigned long B;
   int Result=-1;

#define BMP_Read_0     {if ((iBuff&2047)==0){BMP_fread(Buff,2048,F);iBuff=0;};}
#define BMP_Read_1(X)  {BMP_Read_0;iPos++;X=Buff[iBuff];iBuff++;}
#define BMP_Read_2(X)  {BMP_Read_1(A1);BMP_Read_1(A2);\
                       B=(A2<<8)|A1;\
                       X=(unsigned short)B;}

#define BMP_Read_4(X)  {BMP_Read_1(A1);BMP_Read_1(A2);BMP_Read_1(A3);BMP_Read_1(A4);\
                       B=(((unsigned long)A4)<<24)|(((unsigned long)A3)<<16)|(((unsigned long)A2)<<8)|A1;\
                       X=B;}

#define BMP_Skip_1    {BMP_Read_0;iPos++;iBuff++;}

#define BMP_Skip(N)   {for(ii=0;ii<N;ii++){BMP_Skip_1;};}
#define BMP_Seek(N)   {if(iPos<N){while(iPos<N){BMP_Skip_1;}}else{iPos=N;iBuff=N;};}
#define BMP_Return(N) {Result=N;goto End;}

   int          i,j ;
   unsigned int      ui;

   int Color,Aij;

  //tagBITMAPFILEHEADER
  struct{
            char        bfTypeB       ; // 0000  1
            char        bfTypeM       ; // 0001  1
   unsigned long        bfSize       ; // 0002  4
   unsigned short       bfReserved1  ; // 0006  2
   unsigned short       bfReserved2  ; // 0008  2
   unsigned long        bfOffBits    ; // 000A  4
  }BFH;
  //endBITMAPFILEHEADER

  //tagBITMAPINFOHEADER
  struct{
   unsigned long        biSize       ; // 000E  4
     signed long        biWidth      ; // 0012  4
     signed long        biHeight     ; // 0016  4
   unsigned short       biPlanes     ; // 001A  2
   unsigned short       biBitCount   ; // 001C  2

   unsigned long        biCompression     ; // 001E 4
   unsigned long        biSizeImage       ; // 0022 4
     signed long        biXPelsPerMeter   ; // 0026 4
     signed long        biYPelsPerMeter   ; // 002A 4
   unsigned long        biClrUsed         ; // 002E 4
   unsigned long        biClrImportant    ; // 0032 4
   } BIH;
   //endBITMAPINFOHEADER

   unsigned long        delta =0;
   bool                 NegbiHeight=false;
   #define BMP_ROW (NegbiHeight?(BIH.biHeight-1-i):i)
#ifdef True3Color
    #define BMP_CalcColor(ij) Color = (CL [ij].R*30 + CL [ij].G*59+ CL [ij].B*11) /100;
#else
    #define BMP_CalcColor(ij) Color = (CL [ij].R+ CL [ij].G+ CL [ij].B)/3;
#endif

   struct CL3 {unsigned char R,G,B;};
   CL3 CL[256];

   F = BMP_fopen(lpFileName);

   if (!F) return (-100);

   BMP_Read_1(BFH.bfTypeB);

   if (BFH.bfTypeB != 'B')
   {
      BMP_Return (-1); // Not Bitmap
   }
   BMP_Read_1(BFH.bfTypeM);
   if (BFH.bfTypeM != 'M')
   {
     BMP_Return (-1); // Not Bitmap
   }

   BMP_Read_4(BFH.bfSize           );

   BMP_Read_2(BFH.bfReserved1      );
   if (BFH.bfReserved1 != 0)
   {
     BMP_Return (-1); // Not Bitmap
   }
   BMP_Read_2(BFH.bfReserved2      );
   if (BFH.bfReserved2 != 0)
   {
     BMP_Return (-1); // Not Bitmap
   }
   BMP_Read_4(BFH.bfOffBits        );

   BMP_Read_4(BIH.biSize           );

   if (BIH.biSize >= 40)        // Windows Bitmap
   {
     BMP_Read_4(BIH.biWidth         );
     BMP_Read_4(BIH.biHeight        );
       if(BIH.biHeight<0){BIH.biHeight=-BIH.biHeight;NegbiHeight=true;}

     if ((BIH.biWidth>Wi) || (BIH.biHeight>He))
     {
       BMP_Return(-5);          // too large image
     }

     BMP_Read_2(BIH.biPlanes        );
     BMP_Read_2(BIH.biBitCount      );

     if (BIH.biPlanes!=1)
     {
       BMP_Return(-2);         // unsupported format
     };

     BMP_Read_4(BIH.biCompression   );
     BMP_Read_4(BIH.biSizeImage     );
     BMP_Read_4(BIH.biXPelsPerMeter );
     BMP_Read_4(BIH.biYPelsPerMeter );
     BMP_Read_4(BIH.biClrUsed       );
     BMP_Read_4(BIH.biClrImportant  );

       if (BIH.biClrUsed==0){
       if (BIH.biBitCount==8)BIH.biClrUsed =256;else
       if (BIH.biBitCount==4)BIH.biClrUsed =16;else
       if (BIH.biBitCount==1)BIH.biClrUsed =2;
     }

     for (ui=0;ui<BIH.biClrUsed;ui++)
     {
       BMP_Read_1( CL[ui].B );
       BMP_Read_1( CL[ui].G );
       BMP_Read_1( CL[ui].R );
       BMP_Skip(1);

     }
   }//(biSize != 40)
   else
   if (BIH.biSize==12)             // OS/2 Bitmap
   {
     BMP_Read_2(BIH.biWidth         );
     BMP_Read_2(BIH.biHeight        );
       if(BIH.biHeight<0){BIH.biHeight=-BIH.biHeight;NegbiHeight=true;}

     if ((BIH.biWidth>Wi) || (BIH.biHeight>He))
     {
       BMP_Return(-5);          // too large image
     }

     BMP_Read_2(BIH.biPlanes        );
     BMP_Read_2(BIH.biBitCount      );
     if (BIH.biPlanes!=1)
     {
       BMP_Return(-2);
     };

     if (BIH.biBitCount==8)BIH.biClrUsed =256;else
     if (BIH.biBitCount==4)BIH.biClrUsed =16;else
     if (BIH.biBitCount==1)BIH.biClrUsed =1;else
                           BIH.biClrUsed =0;

     for (ui=0;ui<BIH.biClrUsed;ui++)
     {
       BMP_Read_1( CL[ui].B );
       BMP_Read_1( CL[ui].G );
       BMP_Read_1( CL[ui].R );
     }

   }//(biSize != 40) (biSize != 12)
   else
   {
      BMP_Return(-4);            // not Windows or OS/2 Bitmap
   };

   if (BIH.biBitCount==32)      // truecolor+alpha
   {
   }else
   if (BIH.biBitCount==24)      // truecolor
   {
     delta = (BIH.biWidth*3) %4;
   }else
   if (BIH.biBitCount==8)       // 256 colors
   {
     delta = (BIH.biWidth) %4;
   }else
   if (BIH.biBitCount==4)      // 16 colors
   {
     delta = ((BIH.biWidth+1)/2) %4;
   }else
   if (BIH.biBitCount==1)     // monochrome
   {
     delta = ((BIH.biWidth+7)/8) %4;
   }

   if (delta!=0) delta=4-delta;

   BMP_Seek(BFH.bfOffBits);

   if (BIH.biPlanes==1)
   {
     if ( BIH.biBitCount==32 )
     {
       for (i=BIH.biHeight-1;i>=0;i--)
       {
         for (j=0;j<BIH.biWidth;j++)
         {
           BMP_Skip  ( 1 ); //A
           BMP_Read_1( CL [0].B );
           BMP_Read_1( CL [0].G );
           BMP_Read_1( CL [0].R );
           BMP_CalcColor(0);

           A [BMP_ROW][j] = (unsigned char)Color;

         };
         BMP_Skip(delta);
       };
     }else
     if ( BIH.biBitCount==24 )
     {
       for (i=BIH.biHeight-1;i>=0;i--)
       {
         for (j=0;j<BIH.biWidth;j++){
           BMP_Read_1( CL [0].B );
           BMP_Read_1( CL [0].G );
           BMP_Read_1( CL [0].R );
           BMP_CalcColor(0);

           A [BMP_ROW][j] = (unsigned char)Color;
         };
         BMP_Skip(delta);
       };
     }else
     if ( BIH.biBitCount==8 )
     {
       for (i=BIH.biHeight-1;i>=0;i--){
         for (j=0;j<BIH.biWidth;j++){
           BMP_Read_1( Aij );

           BMP_CalcColor(Aij);

           A [BMP_ROW][j] = (unsigned char) Color;
         }
         BMP_Skip(delta);
       };
     }else
     if ( BIH.biBitCount==4 )
     {
       for (i=BIH.biHeight-1;i>=0;i--)
       {
         for (j=0;j<BIH.biWidth;j++)
         {
           if ((j % 2) ==0 ) BMP_Read_1( AA );
           Aij = AA >>4; AA <<= 4; 

           BMP_CalcColor(Aij);

           A [BMP_ROW][j] = (unsigned char)Color;
           
         };
         BMP_Skip(delta);
       };
     }else
     if ( BIH.biBitCount==1 )
     {
       for (i=BIH.biHeight-1;i>=0;i--){
         for (j=0;j<BIH.biWidth;j++){
           if ((j % 8) ==0 ) BMP_Read_1(AA);
           Aij = AA >>7; AA <<= 1; 
           BMP_CalcColor(Aij);

           A [BMP_ROW][j] = (unsigned char)Color;

         };
         BMP_Skip(delta);
       };
     }else{
       BMP_Return(-2);  //unsupported format
     };
   }else{
     BMP_Return(-2); //unsupported format
   };
   He =BIH.biHeight;
   Wi =BIH.biWidth;

   Result=0;
End:
   BMP_fclose(F);

   return(Result);
   
#undef BMP_Read_4
#undef BMP_Read_2
#undef BMP_Read_1
#undef BMP_Read_N

#undef BMP_Skip
#undef BMP_Seek
#undef BMP_Return

#undef BMP_ROW
#undef BMP_CalcColor

#undef BMP_fopen
#undef BMP_fread
#undef BMP_fclose

}//LoadBMP
const char* LoadBMPResult(int res)
{
  if (res == -1)    return "file - not bitmap ";
  if (res == -2)    return "unsupported format";
  if (res == -4)    return "not Windows or OS/2 Bitmap";
  if (res == -5)    return "too large image  ";

  if (res == -10)   return "impossible maloc ";
  if (res == -100)  return "file not found   ";

  return "?";
}
//---------------------------------------------------------------------------

