/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: gdiblt.cpp,v 1.6.20.1 2004/07/09 01:59:19 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

#include "hxcom.h"
#include "hxtypes.h"
#include "hxwintyp.h"

#ifndef _WINCE
	#include <ddraw.h>
#endif

#include "colormap.h"

#if defined (HELIX_FEATURE_CC_RGB8out)
#include "colorlib.h"
#endif

#include "gdiblt.h"

CGDIBlt::CGDIBlt()
 :  CWinBlt()
 ,  m_pGdiSurface(NULL)
#if defined (HELIX_FEATURE_CC_RGB8out)
 ,  m_nSystemColors(0)
#endif
{
    memset(&m_gdiInfo, 0, sizeof(m_gdiInfo));
}

CGDIBlt::~CGDIBlt()
{
    DestroySurface(0);
}

HX_RESULT CGDIBlt::CreateSurface(int cidIn, int& cidOut,
                                 int nWidth, int nHeight,
                                 int nFlags, HWND hWnd,
                                 int nCountIn, int& nCountOut)
{
    HANDLE      hMapping;       // handle to mapped object
    HBITMAP     hBitmap;        // DIB section bitmap handle
    BYTE        *pBase;         // pointer to the actual image
    BITMAPINFO  *pbmi;
    BYTE        *pbmiBuf = NULL;
    int         nSize = sizeof(BITMAPINFO);
    int         nColors = 0;
    void        *pPalette = NULL;
    HX_RESULT   hr = HXR_OK;

    m_hWnd = hWnd;

#if defined (HELIX_FEATURE_CC_RGB32out)
    m_nCID = CID_RGB32;
#elif defined (HELIX_FEATURE_CC_RGB24out)
    m_nCID = CID_RGB24;
#elif defined (HELIX_FEATURE_CC_RGB565out)
    m_nCID = CID_RGB565;
    nSize += 3 * sizeof(ULONG32);
#elif defined (HELIX_FEATURE_CC_RGB555out)
    m_nCID = CID_RGB555;
    nSize += 3 * sizeof(ULONG32);
#elif defined (HELIX_FEATURE_CC_RGB444out)
    m_nCID = CID_RGB444;
    nSize += 3 * sizeof(ULONG32);
#elif defined (HELIX_FEATURE_CC_RGB8out)
    m_nCID = CID_RGB8;
    nColors = 256;
    nSize += nColors * sizeof(PALETTEENTRY);

    // get system palette first
    HDC hDC = GetDC(NULL);
    PALETTEENTRY SystemPalette[256];
    
    if (hDC) 
    {
        m_nSystemColors = GetSystemPaletteEntries (hDC, 0, 256, SystemPalette);
        ReleaseDC (NULL,hDC);

        // generate palette index
        for (int i=0; i<m_nSystemColors; i++)
        {
	        m_SystemPaletteIndices[i] = i;
	        m_SystemPaletteRGB[i].rgbBlue = SystemPalette[i].peBlue;
	        m_SystemPaletteRGB[i].rgbGreen = SystemPalette[i].peGreen;
	        m_SystemPaletteRGB[i].rgbRed = SystemPalette[i].peRed;
	        m_SystemPaletteRGB[i].rgbReserved = 0;
        }

        // update color converter's palette with the current system palette entries
        SetDestRGB8Palette(m_nSystemColors, (unsigned int *)SystemPalette, m_SystemPaletteIndices);
        pPalette = SystemPalette;
    }
#endif
    
    cidOut = m_nCID;

    // allocate the buffer for the BITMAPINFO
    pbmiBuf = new BYTE[nSize];

    if (!pbmiBuf)
        return HXR_OUTOFMEMORY;

    memset(pbmiBuf, 0, nSize);
    pbmi = (BITMAPINFO*)pbmiBuf;
    
    // initialize the BITMAPINFO values
    MakeBitmap (pbmi, nSize, cidOut, nWidth, nHeight, (PALETTEENTRY*)pPalette, nColors);

    // allocate a new GDISURFACE structure to use:
    m_pGdiSurface = new GDISURFACE;
    
    if (m_pGdiSurface != NULL)
    {
        // create a file mapping object and map into our address space
#ifndef WINCE
        hMapping = CreateFileMapping ((HANDLE) 0xFFFFFFFF,
                                      NULL, PAGE_READWRITE,
                                      (DWORD) 0,
                                      pbmi->bmiHeader.biSizeImage, NULL);
        if (hMapping != NULL)
#else
			hMapping = NULL;
#endif
        {
            // create a DIB section using given image format
#ifdef WINCE
			pBase = NULL;
#endif
            hBitmap = CreateDIBSection ((HDC) NULL, pbmi, DIB_RGB_COLORS, (VOID **) &pBase, hMapping, (DWORD) 0);

            if (hBitmap != NULL && pBase != NULL)
            {
                // initialise the GDISURFACE structure
                m_pGdiSurface->hBitMap = hBitmap;
                m_pGdiSurface->lpBase = pBase;
                m_pGdiSurface->nPitch = nWidth*pbmi->bmiHeader.biBitCount/8;
                m_pGdiSurface->nPitch = -((m_pGdiSurface->nPitch + 3) & ~3);

                // m_pGdiSurface->PaletteVersion = PALETTE_VERSION
                GetObject (hBitmap, sizeof (DIBSECTION), (VOID *)& (m_pGdiSurface->DibSection));
            }
            // close file mapping
#ifndef WINCE
            CloseHandle (hMapping);
#endif

            m_gdiInfo.hDC = GetDC(m_hWnd);
            m_gdiInfo.hMemoryDC = CreateCompatibleDC(m_gdiInfo.hDC);
        }
    }
#ifndef WINCE
    else
        hr = HXR_FAIL;
#endif


    HX_VECTOR_DELETE(pbmi);

    return hr;
}

HX_RESULT CGDIBlt::LockSurface(UCHAR** ppDestPtr,
                              LONG32* pnDestPitch,
                              int& cid,
                              REF(HXxSize) dstSize,
                              int nIndex)
{
    *ppDestPtr = m_pGdiSurface->lpBase;
    *pnDestPitch = m_pGdiSurface->nPitch;
    cid = m_nCID;

    return HXR_OK;
}

HX_RESULT CGDIBlt::FillSurface(int cidIn,
                               UCHAR* pSrcBuffer,
                               HXxSize* pSrcSize,
                               HXxRect* prSrcRect,
                               UCHAR* pDstBuffer,
                               LONG32 nDstPitch,
                               HXxRect* prDestRect)
{
    
    return HXR_NOTIMPL;
}

HX_RESULT CGDIBlt::UnlockSurface(UCHAR* pSurfPtr, int nIndex)
{
    return HXR_OK;
}

HX_RESULT CGDIBlt::RenderSurface(HXxSize* pSrcSize,
                                 HXxRect* prSrcRect,
                                 HXxRect* prDestRect,
                                 int nIndex)
{
    // Map to screen coordinates
    //POINT   po = {0,0};
    //ClientToScreen(m_hWnd, &po);
    
    RECT rc;
    GetClientRect(m_hWnd, &rc);
    
    /*rc.left += po.x;
    rc.right += po.x;
    rc.top += po.y;
    rc.bottom += po.y;*/
    
    BOOL bResult;
    HBITMAP hOldBitmap;
    
    /* get sizes of source/destination rectangles: */
    LONG lTargetWidth  = rc.right  - rc.left;
    LONG lTargetHeight = rc.bottom - rc.top;
    LONG lSourceWidth  = prSrcRect->right  - prSrcRect->left;
    LONG lSourceHeight = prSrcRect->bottom - prSrcRect->top;
    
    /* select bitmap to blit: */
    hOldBitmap = (HBITMAP) SelectObject (m_gdiInfo.hMemoryDC, m_pGdiSurface->hBitMap);
    
#if defined (HELIX_FEATURE_CC_RGB8out)
    SetDIBColorTable(m_gdiInfo.hMemoryDC, 0, m_nSystemColors, m_SystemPaletteRGB);
#endif

    /* is the window the same size as the video: */
    if (lTargetWidth == lSourceWidth && lTargetHeight == lSourceHeight)
    {
	/* put the image straight into the window: */
        bResult = BitBlt (
            m_gdiInfo.hDC,	    /* target device HDC        */
            rc.left,       /* x sink position          */
            rc.top,        /* y sink position          */
            lTargetWidth,           /* destination width        */
            lTargetHeight,          /* destination height       */
            m_gdiInfo.hMemoryDC,    /* source device context    */
            prSrcRect->left,        /* x source position        */
            prSrcRect->top,         /* y source position        */
            SRCCOPY);               /* simple copy              */
	
    } else {
        /* stretch the image when copying to the window: */
        bResult = StretchBlt (
            m_gdiInfo.hDC,	    /* target device HDC        */
            rc.left,       /* x sink position          */
            rc.top,        /* y sink position          */
            lTargetWidth,           /* destination width        */
            lTargetHeight,          /* destination height       */
            m_gdiInfo.hMemoryDC,    /* source device HDC        */
            prSrcRect->left,        /* x source position        */
            prSrcRect->top,         /* y source position        */
            lSourceWidth,           /* source width             */
            lSourceHeight,          /* source height            */
            SRCCOPY);               /* simple copy              */
    }
    /* put the old bitmap back into the device context so we don't leak */
    SelectObject (m_gdiInfo.hMemoryDC, hOldBitmap);
    
    return HXR_OK;
}

HX_RESULT CGDIBlt::DestroySurface(int cid)
{
    if (m_gdiInfo.hDC) 
        ReleaseDC (m_hWnd, m_gdiInfo.hDC);   

    if (m_gdiInfo.hMemoryDC) 
        DeleteDC (m_gdiInfo.hMemoryDC);
    
    memset(&m_gdiInfo, 0, sizeof(m_gdiInfo));

    if (m_pGdiSurface)
    {
        DeleteObject (m_pGdiSurface->hBitMap);
        HX_DELETE(m_pGdiSurface);
    }

    return HXR_OK;
}
