/* ====================================================================================================================

  The copyright in this software is being made available under the License included below.
  This software may be subject to other third party and   contributor rights, including patent rights, and no such
  rights are granted under this license.

  Copyright (c) 2010, SAMSUNG ELECTRONICS CO., LTD. and BRITISH BROADCASTING CORPORATION
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification, are permitted only for
  the purpose of developing standards within the Joint Collaborative Team on Video Coding and for testing and
  promoting such standards. The following conditions are required to be met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and
      the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
      the following disclaimer in the documentation and/or other materials provided with the distribution.
    * Neither the name of SAMSUNG ELECTRONICS CO., LTD. nor the name of the BRITISH BROADCASTING CORPORATION
      may be used to endorse or promote products derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 * ====================================================================================================================
*/

/** \file     TComRdCost.h
    \brief    RD cost computation classes (header)
*/

#ifndef __TCOMRDCOST__
#define __TCOMRDCOST__


#include "CommonDef.h"
#include "TComPattern.h"
#include "TComMv.h"

class DistParam;
class TComPattern;

// ====================================================================================================================
// Type definition
// ====================================================================================================================

// for function pointer
typedef UInt (*FpDistFunc) (DistParam*);

#ifdef ROUNDING_CONTROL_BIPRED
typedef UInt (*FpDistFuncRnd) (DistParam*, Pel*, Bool);
#endif

// ====================================================================================================================
// Class definition
// ====================================================================================================================

/// distortion parameter class
class DistParam
{
public:
  Pel*  pOrg;
  Pel*  pCur;
  Int   iStrideOrg;
  Int   iStrideCur;
  Int   iRows;
  Int   iCols;
  Int   iStep;
  FpDistFunc DistFunc;
#ifdef ROUNDING_CONTROL_BIPRED
  FpDistFuncRnd DistFuncRnd;
#endif

  // (vertical) subsampling shift (for reducing complexity)
  // - 0 = no subsampling, 1 = even rows, 2 = every 4th, etc.
  Int   iSubShift;
  
  DistParam()
  {
    pOrg = NULL;
    pCur = NULL;
    iStrideOrg = 0;
    iStrideCur = 0;
    iRows = 0;
    iCols = 0;
    iStep = 1;
    DistFunc = NULL;
#ifdef ROUNDING_CONTROL_BIPRED
    DistFuncRnd = NULL;
#endif
    iSubShift = 0;
  }
};

/// RD cost computation class
class TComRdCost
{
private:
  // for distortion
  Int                     m_iBlkWidth;
  Int                     m_iBlkHeight;

  FpDistFunc              m_afpDistortFunc[33]; // [eDFunc]
#ifdef ROUNDING_CONTROL_BIPRED
  FpDistFuncRnd           m_afpDistortFuncRnd[33];
#endif

  Double                  m_dLambda;
  UInt                    m_uiLambdaMotionSAD;
  UInt                    m_uiLambdaMotionSSE;
  Double                  m_dFrameLambda;

  // for motion cost
  UInt*                   m_puiComponentCostOriginP;
  UInt*                   m_puiComponentCost;
  UInt*                   m_puiVerCost;
  UInt*                   m_puiHorCost;
  UInt                    m_uiCost;
  Int                     m_iCostScale;
  Int                     m_iSearchLimit;

public:
  TComRdCost();
  virtual ~TComRdCost();

  Double  calcRdCost  ( UInt   uiBits, UInt   uiDistortion, Bool bFlag = false, DFunc eDFunc = DF_DEFAULT );
  Double  calcRdCost64( UInt64 uiBits, UInt64 uiDistortion, Bool bFlag = false, DFunc eDFunc = DF_DEFAULT );

  Void    setLambda      ( Double dLambda );
  Void    setFrameLambda ( Double dLambda ) { m_dFrameLambda = dLambda; }

#if SAMSUNG_FAST_UDI
  Double  getLambda ()   { return m_dLambda; }
#endif

  // Distortion Functions
  Void    init();

  Void    setDistParam( UInt uiBlkWidth, UInt uiBlkHeight, DFunc eDFunc, DistParam& rcDistParam );
  Void    setDistParam( TComPattern* pcPatternKey, Pel* piRefY, Int iRefStride,            DistParam& rcDistParam );
  Void    setDistParam( TComPattern* pcPatternKey, Pel* piRefY, Int iRefStride, Int iStep, DistParam& rcDistParam, Bool bHADME=false );

#ifdef ROUNDING_CONTROL_BIPRED
  Void    setDistParam_Bi( TComPattern* pcPatternKey, Pel* piRefY, Int iRefStride,            DistParam& rcDistParam );
  Void    setDistParam_Bi( TComPattern* pcPatternKey, Pel* piRefY, Int iRefStride, Int iStep, DistParam& rcDistParam, Bool bHADME=false );
#endif
  UInt    getDistLumBlk  ( Pel *piCur, UInt uiBlkWidth, UInt uiBlkHeight, Int iBlkIdx, Int iStride, DFunc eDFunc = DF_SSE );
  UInt    getDistCbBlk   ( Pel *piCur, Int iStride, DFunc eDFunc = DF_SSE );  // 8x8 block only
  UInt    getDistCrBlk   ( Pel *piCur, Int iStride, DFunc eDFunc = DF_SSE );  // 8x8 block only

  UInt    calcHAD         ( Pel* pi0, Int iStride0, Pel* pi1, Int iStride1, Int iWidth, Int iHeight );

  // for motion cost
  Void    initRateDistortionModel( Int iSubPelSearchLimit );
  Void    xUninit();
  UInt    xGetComponentBits( Int iVal );
  Void    getMotionCost( Bool bSad, Int iAdd ) { m_uiCost = (bSad ? m_uiLambdaMotionSAD + iAdd : m_uiLambdaMotionSSE + iAdd); }
  Void    setPredictor( TComMv& rcMv )
  {
    m_puiHorCost = m_puiComponentCost - rcMv.getHor();
    m_puiVerCost = m_puiComponentCost - rcMv.getVer();
  }
  Void    setCostScale( Int iCostScale )    { m_iCostScale = iCostScale; }
  __inline UInt getCost( Int x, Int y )
  {
    return (( m_uiCost * (m_puiHorCost[ x * (1<<m_iCostScale) ] + m_puiVerCost[ y * (1<<m_iCostScale) ]) ) >> 16);
  }
#ifdef QC_AMVRES
  __inline UInt getCost( Int x, Int y ,Int extrabits)
  {
    return (( m_uiCost * (m_puiHorCost[ x * (1<<m_iCostScale) ] + m_puiVerCost[ y * (1<<m_iCostScale) ]+extrabits) ) >> 16);
  }
#endif
  UInt    getCost( UInt b )                 { return ( m_uiCost * b ) >> 16; }
  UInt    getBits( Int x, Int y )           { return m_puiHorCost[ x * (1<<m_iCostScale)] + m_puiVerCost[ y * (1<<m_iCostScale) ]; }

private:

  static UInt xGetSSE           ( DistParam* pcDtParam );
  static UInt xGetSSE4          ( DistParam* pcDtParam );
  static UInt xGetSSE8          ( DistParam* pcDtParam );
  static UInt xGetSSE16         ( DistParam* pcDtParam );
  static UInt xGetSSE32         ( DistParam* pcDtParam );
  static UInt xGetSSE64         ( DistParam* pcDtParam );
  static UInt xGetSSE16N        ( DistParam* pcDtParam );

  static UInt xGetSAD           ( DistParam* pcDtParam );
  static UInt xGetSAD4          ( DistParam* pcDtParam );
  static UInt xGetSAD8          ( DistParam* pcDtParam );
  static UInt xGetSAD16         ( DistParam* pcDtParam );
  static UInt xGetSAD32         ( DistParam* pcDtParam );
  static UInt xGetSAD64         ( DistParam* pcDtParam );
  static UInt xGetSAD16N        ( DistParam* pcDtParam );

  static UInt xGetSADs          ( DistParam* pcDtParam );
  static UInt xGetSADs4         ( DistParam* pcDtParam );
  static UInt xGetSADs8         ( DistParam* pcDtParam );
  static UInt xGetSADs16        ( DistParam* pcDtParam );
  static UInt xGetSADs32        ( DistParam* pcDtParam );
  static UInt xGetSADs64        ( DistParam* pcDtParam );
  static UInt xGetSADs16N       ( DistParam* pcDtParam );

  static UInt xGetHADs4         ( DistParam* pcDtParam );
  static UInt xGetHADs8         ( DistParam* pcDtParam );
  static UInt xGetHADs          ( DistParam* pcDtParam );
  static UInt xCalcHADs2x2      ( Pel *piOrg, Pel *piCurr, Int iStrideOrg, Int iStrideCur, Int iStep );
  static UInt xCalcHADs4x4      ( Pel *piOrg, Pel *piCurr, Int iStrideOrg, Int iStrideCur, Int iStep );
  static UInt xCalcHADs8x8      ( Pel *piOrg, Pel *piCurr, Int iStrideOrg, Int iStrideCur, Int iStep );

#ifdef ROUNDING_CONTROL_BIPRED

  static UInt xGetSSE           ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSSE4          ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSSE8          ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSSE16         ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSSE32         ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSSE64         ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSSE16N        ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );

  static UInt xGetSAD           ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSAD4          ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSAD8          ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSAD16         ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSAD32         ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSAD64         ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSAD16N        ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );

  static UInt xGetSADs          ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSADs4         ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSADs8         ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSADs16        ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSADs32        ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSADs64        ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetSADs16N       ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );

  static UInt xGetHADs4         ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetHADs8         ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xGetHADs          ( DistParam* pcDtParam, Pel* pRefY, Bool bRound );
  static UInt xCalcHADs2x2      ( Pel *piOrg, Pel *piCurr, Int iStrideOrg, Int iStrideCur, Int iStep, Pel* pRefY, Int refYStride, Bool bRound );
  static UInt xCalcHADs4x4      ( Pel *piOrg, Pel *piCurr, Int iStrideOrg, Int iStrideCur, Int iStep, Pel* pRefY, Int refYStride, Bool bRound );
  static UInt xCalcHADs8x8      ( Pel *piOrg, Pel *piCurr, Int iStrideOrg, Int iStrideCur, Int iStep, Pel* pRefY, Int refYStride, Bool bRound );

#endif

public:
  UInt   getDistPart( Pel* piCur, Int iCurStride,  Pel* piOrg, Int iOrgStride, UInt uiBlkWidth, UInt uiBlkHeight, DFunc eDFunc = DF_SSE );

};// END CLASS DEFINITION TComRdCost


#endif // __TCOMRDCOST__

