/**********************************************************************

Copyright(c) Analog Devices, Inc. All Rights Reserved. 

This software is proprietary and confidential.  By using this software 
you agree to the terms of the associated Analog Devices License Agreement.  

$RCSfile: BitmapViewer.c,v $
$Revision: 1.1 $
$Date: 2008/06/06 06:00:27 $

Description:
	
******************************************************************************

Include files

*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <drivers/adi_dev.h>			// Device manager includes
#include "mediaplayer.h"
#include <BitmapViewer.h>

/*****************************************************************************
    BMP header (or at least, the bits we use)
*****************************************************************************/
#pragma pack(2)
typedef struct __BitMapHeaderStruct {
    u16    signature;       /* 0x4d42                         */
    u32    file_size;       /* in bytes, unreliable           */
    u16    reserved_1;
    u16    reserved_2;
    u32    data_offset;     /* in bytes, to start of RGB data */
    u32    constant_1;
    u32    pixels_w;        /* image width in pixels          */
    u32    pixels_h;        /* image height in pixels         */
    u16    constant_2;
    u16    bits_per_pixel;  /* we check for 24 (RGB)          */
    u32    compression;
    u32    image_size;      /* in bytes, size of image data   */
    u32    resolution_h;
    u32    resolution_v;
    u32    num_colours_1;
    u32    num_colours_2;
} BITMAP_HEADER_STRUCT;
#pragma pack()

/****************************************************************************

    Function:      DisplayBitmap

    Description:   Opens and displays the given BMP file

*****************************************************************************/
u32 DisplayBitmap(
    char                *szFileName,
    u8                  *pVideoDataBuffer
){
    /*** Variables used to hold display device parameters ***/
    /* Display Pixels Per Line */
    u32 nDisplayPixelsPerLine;
    /* Display Lines Per Frame */
    u32 nDisplayLinesPerFrame;
    /* Display Data Per Pixel */
    u8 nDisplayDataPerPixel;
    /* Display Data Per Line */
    u32 nDisplayDataPerLine;
    
    /*** Variables used for Bitmap file handling ***/
    /* File pointer to a BMP file */
    FILE *pBMPFile;
    /* EOF indicator */
    int nEndOfFile;
    /* BMP file header area */
    BITMAP_HEADER_STRUCT oBMPHeader;
    
    /*** Variables used to center/crop the image to fit the LCD screen ***/
    /* Number of rows to be read from the bitmap image file */
    u32 nNumRowsToRead;
    /* Actual number of bytes to be read per row of a bitmap image */
    u32 nNumBytesToReadPerRow;
    /* Bitmap image height and width */
    u32 nImageWidth, nImageHeight;
    /* Number of bitmap image bytes to skip per row */
    u32 nBMPSkipBytesPerRow;
    /* Number of LCD display buffer bytes to skip per row */
    u32 nLCDSkipBytesPerRow;
    /* Number of LCD display buffer bytes to skip before copying Bitmap data */
    u32 nLCDSkipBytesToStart;
    /* Bitmap padding */
    u32 nBMPPadding;
    /* Offset to read bitmap image data */
    u32 nBMPOffset;
    
    /* DD/SS Result */
    u32 nResult = ADI_DEV_RESULT_SUCCESS;
    
    /* Temp pointer to video data buffer */
    u8  *ptVideoDataBuffer;
    /* Pointer to display line buffer */
    u8  *pDisplayLineBuffer;
    
    /*** Variables used to convert BGR to RGB ***/
    u8  nR,nB;
    u32 nCount;
    
    
    nDisplayPixelsPerLine = LCD_WIDTH;
    nDisplayLinesPerFrame = LCD_HEIGHT;
    nDisplayDataPerPixel  = LCD_DATA_PER_PIXEL;
    nDisplayDataPerLine   = nDisplayPixelsPerLine*3;

    if (nResult == ADI_DEV_RESULT_SUCCESS)
    { 
        /* Open the BMP file */
        pBMPFile = fopen(szFileName, "rb" );
    
        /* IF (successfully opened BMP file) */
        if (pBMPFile)
        {
            /* read the BMP file header */
            if (fread(&oBMPHeader, sizeof(BITMAP_HEADER_STRUCT), 1, pBMPFile) != 1) 
            {
                printf("Failed to read BMP file header!\n");
                nResult = ADI_DEV_RESULT_FAILED;
            }
            else
            {
                /*** Check for valid BMP file ***/
        
                /* Check the signature */
                if (oBMPHeader.signature != 0x4D42U) 
                {
                    printf("Failed to verify BMP header signature\n");
                    nResult = ADI_DEV_RESULT_FAILED;
                }
                /* check the bits-per-pixel (we only do 24 [RGB]) */
                else if (oBMPHeader.bits_per_pixel != (nDisplayDataPerPixel * 8)) 
                {
                    printf("BMP bits-per-pixel not supported: %d\n", oBMPHeader.bits_per_pixel);
                    nResult = ADI_DEV_RESULT_FAILED;
                }
                /* BMP file is valid */
                else
                {
                    /* Get Bitmap image width and height */
                    nImageWidth     = oBMPHeader.pixels_w;
                    nImageHeight    = oBMPHeader.pixels_h;
                    
                    /* Offset to reach Bitmap image data */
                    nBMPOffset      = oBMPHeader.data_offset;
                    
                    /* Calculate Bitmap padding per row */        
                    /* IF (bitmap image boundary must be adjusted) */
                    if ((nImageWidth * nDisplayDataPerPixel) & 0x03U)
                    {
                        nBMPPadding = (0x04U - ((nImageWidth * nDisplayDataPerPixel) & 0x03U));
                    }
                    /* ELSE (bitmap image placed exactly at 32-bit boundary) */
                    else
                    {
                        nBMPPadding  = 0;
                    }
                    
                    /* IF (Bitmap Image width exceeds display width) */
                    if (nImageWidth >= nDisplayPixelsPerLine)
                    {
                        /* Calculate number of bitmap image bytes to skip per row (to crop the image) */
                        nBMPSkipBytesPerRow     = (((nImageWidth - nDisplayPixelsPerLine) * nDisplayDataPerPixel) + nBMPPadding);
                        /* Calculate Actual number of bytes to be read per row of a bitmap image */
                        nNumBytesToReadPerRow   = nDisplayDataPerLine;
                        /* Calculate number of LCD display buffer bytes to skip per row (to center the image) */
                        nLCDSkipBytesPerRow     = 0;
                    }
                    /* ELSE (Bitmap Image width is with in display width) */
                    else
                    {
                        /* Calculate number of bitmap image bytes to skip per row (to crop the image) */
                        nBMPSkipBytesPerRow     = nBMPPadding;
                        /* Calculate Actual number of bytes to be read per row of a bitmap image */
                        nNumBytesToReadPerRow   = (nImageWidth * nDisplayDataPerPixel);
                        /* Calculate number of LCD display buffer bytes to skip per row (to center the image) */
                        nLCDSkipBytesPerRow     = ((nDisplayPixelsPerLine - nImageWidth) * nDisplayDataPerPixel) ;
                    }

                    /* IF (Bitmap Image height exceeds display height) */
                    if (nImageHeight > nDisplayLinesPerFrame)
                    {
                        /* Calculate number of rows to be read from the bitmap image file */
                        nNumRowsToRead          = nDisplayLinesPerFrame;
                        /* Calculate number of LCD display buffer bytes to skip before
                        copying Bitmap data (to center the image) */
                        nLCDSkipBytesToStart    = 0;
                    }
                    /* ELSE (Bitmap Image height is with in display height) */
                    else
                    {
                        /* Calculate number of rows to be read from the bitmap image file */
                        nNumRowsToRead          = nImageHeight;
                        
                        /* IF (Bitmap image has odd number of rows (Image Height)) */
                        if (nImageHeight & 0x01)
                        {
                            /* Adjust the image height to be in even numbers */
                            nImageHeight++;
                        }
                        
                        /* Calculate number of LCD display buffer bytes to skip before
                           copying Bitmap data (to center the image) */
                        nLCDSkipBytesToStart = (((nDisplayLinesPerFrame - nImageHeight) * nDisplayDataPerLine) / 2) ;
                    }
                        
                    /*** Set up Display buffer and Bitmap File pointer positions ***/
                    /* Scan lines in a bitmap image are stored from bottom up
                       This means that the first byte of the valid image data 
                       represents the pixels in the lower-left corner of the display
                       and the last byte represents the pixels in the upper-right corner
                    */

                    /* Clear Video Data Buffer */
                    memset((void*)(pVideoDataBuffer), 0, (480*272*3));
                    /* Reset Temp Display buffer pointer to point last byte of the display buffer */
                    ptVideoDataBuffer  = (pVideoDataBuffer + (nDisplayDataPerLine * nDisplayLinesPerFrame));

                    /* IF (we've anything to read) */
                    if (nNumRowsToRead != 0)
                    {
                        /* Skip the LCD rows that are not going to be used */
                        ptVideoDataBuffer -= nLCDSkipBytesToStart;

                        /* Read Bitmap Image to Ez-Kit memory */
                        for (; nNumRowsToRead; nNumRowsToRead--)
                        {
                            /* Move to start of the LCD display line to be filled */
                            ptVideoDataBuffer -= nDisplayDataPerLine;
                            /* Get display line buffer address */
                            pDisplayLineBuffer = ptVideoDataBuffer;
                            
                            /* Skip first half the number of bytes marked to skip for each LCD row */
                            pDisplayLineBuffer += (nLCDSkipBytesPerRow/2);

                            /* Reset BMP File pointer to fist valid byte of the row */
                            fseek(pBMPFile, nBMPOffset, SEEK_SET);
                                               
                            /* Copy bitmap image row data to LCD buffer */
                            if(fread(pDisplayLineBuffer, nNumBytesToReadPerRow, 1, pBMPFile) != 1)
                            {
                                printf("Failed to read the BMP file: \"%s\"\n", szFileName);
                                nResult = ADI_DEV_RESULT_FAILED;
                                break;
                            }

                            /* Convert BGR to RGB */
                            for (nCount = nNumBytesToReadPerRow; nCount;)
                            {
                                /* Read B */
                                nB = *pDisplayLineBuffer;
                                /* Read R */
                                nR = *(pDisplayLineBuffer + 2U);
                                /* Swap R & B */
                                *pDisplayLineBuffer = nR;
                                *(pDisplayLineBuffer + 2U) = nB;
                                /* Move to next pixel data */
                                pDisplayLineBuffer += nDisplayDataPerPixel;
                                nCount -= nDisplayDataPerPixel;
                            }
                           
                            /* Move to next row in the Bitmap image */
                            nBMPOffset += (nNumBytesToReadPerRow + nBMPSkipBytesPerRow);
                        }
                    }
                    else
                    {
                        printf("BMP file: \"%s\" size is zero!\n", szFileName);
                        nResult = ADI_DEV_RESULT_FAILED;
                    }
                }
            }
            /* close this BMP File file */
            fclose(pBMPFile);
        }
        else
        {
            printf("Failed to open BMP file: \"%s\"\n", szFileName);
            nResult = ADI_DEV_RESULT_FAILED;
        }
    }
    
    /* return */
    return (nResult);
}

/****************************************************************************

    Function:      DisplayRAW

    Description:   Opens and displays the given RAW file

*****************************************************************************/
u32 DisplayRAW(
    char                *file_path,
    u8                  *pVideoDataBuffer
){
	
	FILE *filein;
	u32 Result= ADI_DEV_RESULT_SUCCESS;
    
    filein = fopen(file_path,"rb");
    if (filein)
    {
	    fseek(filein,0,SEEK_SET);
    	fread(pVideoDataBuffer, 1, 480*272*3, filein);
    	fclose(filein);    
    }
    else
    {
    	printf("Failed to open file: \"%s\"\n", file_path);
        Result = ADI_DEV_RESULT_FAILED;
    }	
    return (Result);
}    




/****/
