/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: macyuvblt.cpp,v 1.1.1.1.42.1 2004/07/09 01:59:02 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"
#include "hxvsurf.h"
#include "colormap.h"

#include "macyuvblt.h"


CMacYUVBlt::CMacYUVBlt()
 :  CMacBlt()
 , m_Window(NULL)
 , m_ImageDescriptionHandle(NULL)
 , m_SequenceID(NULL)
 , m_nOverlaySourceWidth(0)
 , m_nOverlaySourceHeight(0)
 , m_nOverlayRowBytes(0)
 , m_nOverlayBufferSize(0)
 , m_pOverlayBuf(NULL)
{
    m_OverlayScreenRect.left = 0;
    m_OverlayScreenRect.top = 0;
    m_OverlayScreenRect.right = 0;
    m_OverlayScreenRect.bottom = 0;
}

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

HX_RESULT CMacYUVBlt::CreateSurface(int cidIn, int& cidOut,
                                 int nWidth, int nHeight,
                                 int nFlags, HWND hWnd,
                                 int nCountIn, int& nCountOut)
{


    // xxxbobclark
    // I think the CreateSurface/DestroySurface pair only care about the
    // "source" parameters. I'll have to maintain the screen output more
    // myself. So -- again, in theory -- I should be able to set up the
    // member variables that get passed "outside" here and in DestroySurface
    // -- variables like m_nOverlayRowBytes, m_nOverlayBufferSize, and
    // m_pOverlayBuf.
    //
    // Then we'll monitor ourselves and notice when we need to destroy and
    // construct the actual image sequence (overlay).


#if defined (HELIX_FEATURE_CC_YUY2out)
    m_nCID = CID_YUY2;
#endif
    
    cidOut = m_nCID;
    
    m_Window = (WindowPtr)hWnd;
    
    // xxxbobclark OK there needs to be a slight architectural change here
    // I'm afraid. We used to construct the sequence and the overlay buffer,
    // buffer size, and overlay row bytes all at the same time.
    //
    // But now we need to know the buffer/size/rowbytes BEFORE we know what
    // the location is going to be. So we'll figure those out "by hand"
    // and not at blit time
    
    m_nOverlaySourceWidth = nWidth;
    m_nOverlaySourceHeight = nHeight;
    _CreateYUVBuffer();

    return HXR_OK;
}

HX_RESULT CMacYUVBlt::LockSurface(UCHAR** ppDestPtr,
                              LONG32* pnDestPitch,
                              int& cid,
                              REF(HXxSize) srcSize,
                              int nIndex)
{
    *ppDestPtr = (UCHAR*) m_pOverlayBuf;
    *pnDestPitch = m_nOverlayRowBytes;

    cid = CID_YUY2;

    return HXR_OK;
}

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

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

HX_RESULT CMacYUVBlt::RenderSurface(HXxSize* pSrcSize,
                                 HXxRect* prSrcRect,
                                 HXxRect* prDestRect,
                                 int nIndex)
{
    if (m_OverlayScreenRect != *prDestRect)
    {
	if (m_SequenceID)
	{
	    _CleanUpOverlay();
	}
	if (!m_SequenceID)
	{
	    _CreateOverlay(prDestRect->left, prDestRect->top, prDestRect->right-prDestRect->left, prDestRect->bottom-prDestRect->top);
	}
    }

    GrafPtr savePort;
    ::GetPort( &savePort );
    GrafPtr theWindowPort = ::GetWindowPort( m_Window );
    ::SetPort( theWindowPort );
    
    DecompressSequenceFrameWhen(
		m_SequenceID,
		(Ptr)m_pOverlayBuf, m_nOverlayBufferSize,
		0, // flags
		nil,
		nil,
		nil);
    
    ::SetPort( savePort );
    
    return HXR_OK;
}

HX_RESULT CMacYUVBlt::DestroySurface(int cid)
{
    return HXR_OK;
}


void CMacYUVBlt::_CreateYUVBuffer()
{
    m_nOverlayRowBytes = m_nOverlaySourceWidth * 2;
    m_nOverlayBufferSize = m_nOverlaySourceHeight * m_nOverlayRowBytes;
    m_pOverlayBuf = ::NewPtr( m_nOverlayBufferSize );
}

void CMacYUVBlt::_CreateOverlay(long screenCoorX, long screenCoorY, long screenWidth, long screenHeight)
{
    ComponentDescription cd;
    Component c = NULL;
    Component foundComponent = NULL;

    cd.componentType = 'imdc';
    cd.componentSubType = 'yuvs';
    cd.componentManufacturer = 'RNWK';
    cd.componentFlags = 0;
    cd.componentFlagsMask = 0;
    
    while ((c = FindNextComponent(c, &cd)) != 0)
    {
	foundComponent = c;
	break;
    }

    // this chunk o' code assumes local coordinates.

    Rect srcR, dstR;

    srcR.left = 0;
    srcR.top = 0;
    srcR.right = m_nOverlaySourceWidth;
    srcR.bottom = m_nOverlaySourceHeight;

    m_OverlayScreenRect.left = screenCoorX;
    m_OverlayScreenRect.top = screenCoorY;
    m_OverlayScreenRect.right = screenCoorX + screenWidth;
    m_OverlayScreenRect.bottom = screenCoorY + screenHeight;
    
    dstR.left = m_OverlayScreenRect.left;
    dstR.top = m_OverlayScreenRect.top;
    dstR.right = m_OverlayScreenRect.right;
    dstR.bottom = m_OverlayScreenRect.bottom;

    m_ImageDescriptionHandle = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));

    (**m_ImageDescriptionHandle).idSize = sizeof(ImageDescription);
    (**m_ImageDescriptionHandle).cType = 'yuvs';
    (**m_ImageDescriptionHandle).width = srcR.right-srcR.left;
    (**m_ImageDescriptionHandle).height = srcR.bottom-srcR.top;
    (**m_ImageDescriptionHandle).hRes = 72L << 16;
    (**m_ImageDescriptionHandle).vRes = 72L << 16;
    (**m_ImageDescriptionHandle).frameCount = 1;
    (**m_ImageDescriptionHandle).clutID = -1;

    MatrixRecord matrix;

    RectMatrix(&matrix, &srcR, &dstR);

    OSErr err = DecompressSequenceBeginS(
			&m_SequenceID,
			m_ImageDescriptionHandle,
			nil, 0, // data pointer and data length
			nil, // use the current port
			nil, // go to screen
			&srcR,
			&matrix,
			ditherCopy,
			nil,
			codecFlagUseImageBuffer,
			codecNormalQuality,
			foundComponent);
}

void CMacYUVBlt::_CleanUpOverlay()
{
    CDSequenceEnd(m_SequenceID);
    m_SequenceID = NULL;
    DisposePtr((Ptr)m_pOverlayBuf);
    m_pOverlayBuf = nil;
    m_nOverlayRowBytes = 0;
    m_nOverlayBufferSize = 0;

    DisposeHandle((Handle)m_ImageDescriptionHandle);
    m_ImageDescriptionHandle = NULL;
}

