///////////////////////////////////////////////////////////
//                                                       //
//  PC MAGAZIN - Demo Projekt                            //
//                                                       //
//  Hier sind die Routinen untergebracht, die es         //
//  ermöglichen, ein Windows BMP File zu laden           //
//                                                       //
///////////////////////////////////////////////////////////

#include "demo.h"

int bmp_load( char *name, bitmaptype &bitmap )
{
    BITMAPFILEHEADER bfh;
    BITMAPINFOHEADER bih;
    HFILE infile;

    ZeroMemory( &bitmap, sizeof( bitmaptype ) );
    infile = _lopen( name, OF_READ );

    if ( infile == HFILE_ERROR ) 
        return BMP_ERROR_FILEOPEN;

    // BMP Headers laden
    _lread( infile, &bfh, sizeof( bfh ) );
    _lread( infile, &bih, sizeof( bih ) );

    // prüfe Kompression und Format
    if ( ( bih.biPlanes != 1 )          ||
         ( bih.biCompression != BI_RGB) ||
         ( bih.biBitCount < 8)          ||
         ( bfh.bfType != 0x4d42 ) )
    {
        _lclose( infile );
        return BMP_ERROR_FORMAT;
    }

    // bereite Header vor
    bitmap.width        = bih.biWidth;
    bitmap.height       = bih.biHeight;
    bitmap.bytesperline = 
        ( (bih.biWidth * bih.biBitCount + 31) >> 5 ) << 2;
    bitmap.pixelbits    = bih.biBitCount;

    // Farb-Tabelle laden und konvertieren
    if ( ( bih.biClrUsed == 0 ) && 
         ( bih.biBitCount == 8 ) )
        bih.biClrUsed = 256;
    
    if ( bih.biClrUsed )
    {
        bitmap.lColors = (long *)malloc( 4 * 256 );
        
        _lread( infile, bitmap.lColors, 
            bih.biClrUsed * sizeof( RGBQUAD ) );

        // Umwandeln von BGR nach RGB
        for ( int i = 0; i < 256; i++ )
        {
            int b = bitmap.cColors[ i * 4 ];
            int g = bitmap.cColors[ i * 4 + 1 ];
            int r = bitmap.cColors[ i * 4 + 2 ];
            bitmap.lColors[ i ] = r | (g<<8) | (b<<16);
        }
    }

    // das Vorzeichen der height gibt an, ob das Bitmap
    // topdown oder bottomup gespeichert ist.. Im Speicher
    // wird es immer topdown sein.
    bitmap.cBitmap = (unsigned char *)
        malloc( bitmap.height * bitmap.bytesperline );
    
    if ( bih.biHeight < 0 )
    {
        for ( int i = 0; i < -bih.biHeight; i++ )
            _lread( infile, 
                    bitmap.cBitmap + i*bitmap.bytesperline,
                    bitmap.bytesperline );
    } else 
    {
        for ( int i = bih.biHeight - 1; i >= 0; i--)
            _lread( infile, 
                    bitmap.cBitmap + i*bitmap.bytesperline,
            bitmap.bytesperline );
    }

    _lclose( infile );
    
    return BMP_NOERROR;
}


// Freigeben des Speichers
void bmp_free( bitmaptype &bitmap )
{
    if ( bitmap.cBitmap ) free( bitmap.cBitmap );
    if ( bitmap.cColors ) free( bitmap.cColors );
    ZeroMemory( &bitmap, sizeof( bitmaptype ) );
}


// Umwandeln in 16 Bit Farben
void bmp_make16bitpalette( bitmaptype &bitmap )
{
    if ( bitmap.cColors )
    {
        short *palette = (short *)malloc( 256 * 2 );
        for ( int i = 0; i < 256; i++ )
        {
            int r = bitmap.cColors[ i * 4 ];
            int g = bitmap.cColors[ i * 4 + 1 ];
            int b = bitmap.cColors[ i * 4 + 2 ];
            palette[i] = Rtab[ r ] |
                         Gtab[ g ] |
                         Btab[ b ];
        }
        free( bitmap.cColors );
        bitmap.sColors = palette;
    }
}

