/*  c.jhbmp

    BMP pre-decode routines for FYEO2

    by Rick Murray 2004

    Last modified 2004/02/25, at 01:52 CET
*/



#include "Erreur.h"
#include "Bool.h"
#include <stdio.h>
#include "Modes.h"




#define JFREAD(file,buf,sizeofbuf)  \
                                ((size_t) fread((void *) (buf), (size_t) 1, (size_t) \
                                 (sizeofbuf), (file)))

#define LM_to_uint(a,b)         ((((b)&0xFF) << 8) | ((a)&0xFF))

#define BitSet(byte, bit)       ((byte) & (bit))

#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))

#define COLORMAPFLAG    0x80    /* mask for bit signifying colormap presence */




// leave these global so we can fuck around with them from "jrdbmp.c"...
char bmp_header[64];
int  bmp_bpp = 0;
int  bmp_start = 0;
int  bmp_size = 0;




int BMP_PullWord(int offset)
{
   // Swap the bytes in a word (I'm not smart enough to do a 'sexy' one-line macro).

   int  out = 0;

   out  =  bmp_header[offset++];
   out += (bmp_header[offset++] <<  8);
   out += (bmp_header[offset++] << 16);
   out += (bmp_header[offset++] << 24);

   return out;
}



BOOL is_bmp(char *Filename)
{
   FILE *File;
   char idbuf[4] = "";
   BOOL  reply = FALSE;

   File = fopen(Filename, "r");

   if (ReadOK(File, idbuf, 3))
      reply = (idbuf[0] == 'B' && idbuf[1] == 'M');

   fclose(File);
   return (reply);
}



void get_bmp_size(char *Filename, int *Width, int *Height)
{
   /* This function reads information from the BMP header...

         // BITMAP_FILE_HEADER
         char  file_id[2];        //  0  'B' then 'M'
         int   file_length;       //  2  File length in bytes
         int   reserved;          //  6  (should be zero)
         int   image_data;        // 10  Offset to image data

         // BITMAP_INFO_HEADER
         int   header_length;     // 14  Length, in bytes, of this header block
         int   width;             // 18  Image width, pixels
         int   height;            // 22  Image height, pixels
         short planes;            // 26  Colour planes, should be '1'
         short bpp;               // 28  Bits-per-pixel (is 1, 4, 8, or 24)
         int   compression;       // 30  Compression type - 0=None, 1=RLE8, 2=RLE4
         int   image_size;        // 34  Image data area size, in bytes
         int   resolution_h;      // 38  Pixels/metre horizontally
         int   resolution_v;      // 42  Pixels/metre vertically
         int   colours;           // 46  How many colours the image uses [*NOTE 1*]
         int   important_colours; // 50  How many of the defined colours are important [*NOTE 2*]

         // If palette, then colour defs follow...
         //
         // ** COLOURS ARE ORDERED ACCORDING TO THEIR 'importance' IN THE COLOUR TABLE **



         NOTE 1: The colour table is normally defined for <24bpp and is 0 for 24bpp; HOWEVER
                 it CAN be non-0 at 24bpp. My book says "for optimisation reasons", but since
                 24bpp carries the red/green/blue values instead of palette values, I don't
                 know what the hell THAT is supposed to mean! If the image is 24bpp, we'll
                 simply ignore any colour definitions.

                 The value for 'colours used' can be smaller than the colour table holds.
                 The size of the colour table is FIXED according to the bpp (i.e. 8bpp
                 implies 256 colours).

         Note 2: This specifies which colours are considered important, or 0 to mean 'all'.
                 One would assume that if you have a 16 colour screen, then the best results
                 will occur if you define the first ~16 colours (since they are in order of
                 importance) and then ColourTrans to those 16 colours...
                 Thing is, though, does anything (except anal software) actually bother to
                 sort the colour table in this way?
   */

   char idbuf[4];
   int  colormaplen, c;
   FILE *File = NULL;
   int  width, height, bpp, start, size;

   File = fopen(Filename, "r");

   if (!ReadOK(File, idbuf, 3))
   {
      fclose(File);
      erreur_fatal("This is not a BMP file");
   }

   if (idbuf[0] != 'B' || idbuf[1] != 'M')
   {
      fclose(File);
      erreur_fatal("This is not a BMP file");
   }

   rewind(File);
   if (fread( &bmp_header, 54, 1, File) != 1)
      erreur_fatal("Premature EOF in BMP file");

   fclose(File);

   *Width    =  BMP_PullWord(18);
   *Height   =  BMP_PullWord(22);
   bmp_bpp   = (BMP_PullWord(28) & 0xFFFF);
   bmp_start =  BMP_PullWord(10);
   bmp_size  =  BMP_PullWord(34);

   return;
}



void get_bmp_bpp_and_colorspace(char *Filename,int *Bpp,int *Colorspace)
{
   *Bpp = bmp_bpp;

   switch (bmp_bpp)
   {
      case 1 : // 1 bpp, monochromatic
               *Colorspace = FYEO_COLORMAPED;
               break;

      case 4 : // 4 bpp, 16 colour
               *Colorspace = FYEO_COLORMAPED;
               break;

      case 8 : // 8 bpp, 256 colour
               *Colorspace = FYEO_COLORMAPED;
               break;

      case 24: // 24 bpp, "Trucolor"  <-- two incorrectly spelled words concatenated!
               *Colorspace = FYEO_RGB;
               break;

      default: // anything else is incorrect
               erreur_fatal("Invalid bpp in BMP file");
               //
               // That reads like French stuff:
               //   Take your bpp to the BMP via the FNAC and the CPAM will extract money from
               //   the DAB and pass it via ISPA and the EDPD so you can pay EDF/GDF and put
               //   the rest in the CN at the CMB so the FNAIF guys don't get it.
               //
               //   The French, apparently, LOVE to reduce stuff to acronyms: it is bloody
               //   annoying when you are looking for something in a town with lots of good
               //   signposting, but everything is just a bunch of letters. Would it hurt /so/
               //   much to write "Maison de Centre Sociale" instead of "MCS"? This sort of stuff
               //   stuff is *NOT* in a dictionary ... would anybody from, like, the Alsace
               //   visiting le pays de Bretagne realise that "CMB" is a bank?!?
               //
               //   PS: If you happen to know French, don't bother correcting my (mostly)
               //       incorrect genders... I can't think of a fork as being male or female,
               //       or even (god help it) homosexual. Yes, you can tell me lots of jokes
               //       about the act of "forking" now, thank you.
               //       Okay, done?
               //       Anyway, I don't see a fork as possessing a gender, and I don't think I
               //       ever will. A fork is a metal implement that you poke into bits of sausage
               //       to assist it (the sausage) in it's journey from the plate to your mouth.
               //       Unless you're a Unix programmer or a randonee freak, in which case forks
               //       are slightly more interesting (but not by much).
               //
               //       I'm going to stop eating the pasta in front of me, and I'm going to
               //       contemplate my fork...
               //
               //       [...minutes pass...]
               //
               //       Nope, sorry. I can't assign a gender to it. It's just a friggin' fork!
               //
               //
               //  PPS: In case you, like, care, or something...
               //
               //       fork (noun)  Eating implement:           forchette (fem.)
               //                    Tool:                       fourche (fem.)
               //                    Division, in river or tree: fourche (fem.)
               //                    Division, in road:          bifurcation (fem.)
               //                    Division, in railway:       embranchment (masc.)
               //
               //       There's always one, huh? :-)
               //
               //       A quick translation:
               //         I'm forked if I know     ->  Je n'en sais fourche rien!  [**NOTE**]
               //
               //       Note: Be careful how you pronounce this, it is very
               //             close to how you'd say the 'rude' phrase. :-)
               //
               //
               // PPPS: Yes, I used a dictionary. If I actually *knew* all that crap, I would
               //       be able to, like, parlays fransays. Okay, I'm not THAT bad, but no
               //       matter how much I try to tell the cute girl in McDo "chocolat chaud",
               //       she simply *doesn't* understand me...
               //       So I'm like:
               //          La machine pour le caf, oui? Mais pas caf et pas th, l'autre?
               //       At this point she'd say "Hup! Chocolat chaud!" and it would sound EXACTLY
               //       like what I'm trying to say.
               //       If she wasn't so cute (though, depressingly, not so bright), I'd start
               //       having visions of D-FENS and the WhammyBurger. Jeez...
               //

   } // Here endeth the switch... If this fails to compile, it is
     // because your compiler read the above and died of boredom...
}
