/* The copyright in this software is being made available under the BSD
 * 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-2012, ITU/ISO/IEC
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are 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 the ITU/ISO/IEC nor the names of its contributors 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.
 */


/*
 * In addition to the orignal authors, this software was further modified by the following parties:
 *
 * Authors:
 *      Lu  Yu,    yul@zju.edu.cn (Zhejiang University)
 *      Yin Zhao,  zhao87099664@163.com  (Zhejiang University)
 *      <new contributor name>, <email>, <affiliation>
 *
 * The related parities retain full right to their code for their own purpose, assign or donate the cooresponding
 * code to another party and to inhibit third parties from using the code for products that do not conform 
 * to MPEG-related and/or ISO/IEC International Standards. 
 *
 */

#ifndef VISBD_H
#define VISBD_H


typedef struct disparity_table
{
#if NTT_SUBPEL_VSP_M24796
  int integer;
  int fractional;
#if QC_VSP_Asymmetric_Resolution// NTT
#if NTT_VSP_HARMONIZATION_M25195
  int integerUV;
  int fractionalUV;
#else // NTT_VSP_HARMONIZATION_M25195
  int targetUV;
  int referenceUV;
  int referenceY[2];
#endif // NTT_VSP_HARMONIZATION_M25195
#endif // (QC_VSP_Asymmetric_Resolution)
#else // NTT_SUBPEL_VSP_M24796
	int int_disparity;
	double db_disparity;
	double db_disparity_mul2;
	double db_disparity_mul4;
#endif // NTT_SUBPEL_VSP_M24796
}DisparityTable;




class CViewInterpolation1D
{
private:
  int Width;                //!> Picture resolution
  int Height;
  int Width2;               //!> The width when the ref view is upsampled (may be 2*Width or 4*Width, it depends). otherwise, it is the same as Width
  int SubPelOption;         //!> 1: Map the pixel to integer pixels. 2: to half pixels. 
  int UpsampleRefs;         //!> 1: No upsampling refs; 2: Upsampling refs;
                            //!> Note that: half pixel precision is obtained by SubPelOption = 2 and UpsampleRefs = 1
                            //!>quar pixel precision is obtained by SubPelOption = 2 and UpsampleRefs = 2
  int SplattingOption;      //!> 0: Disable Splatting; 1: Enable Splatting Globally; 2: Enable Splatting only around boundaries
  int BoundaryGrowth;       //!> Boundary dialation, useful for Splatting option 2
  int MergingOption;        //!> 0: Z_buffer; 1: camera distance weighting; 2: Z_buffer + hole counting + camera distance weighting
#if NOKIA_DISP_CALC_B0150
  int** DisparityLUTL;     //!< disparity look up table for the left view [0:quarter-pel, 1:half-pel][depth_value]
  int** DisparityLUTR;     //!< disparity look up table for the right view [0:quarter-pel, 1:half-pel][depth_value]
#else
  double FocalLength;       //!> focal length. it is assumed that all cameras share the same focal length
  double LTranslation[2];   //!> The camera distance from the left (0) and right (1) camera
  double duPrincipal[2];    //!> The diff in principal point offset from left (0) and right (1) camera
  double Znear[2];          //!> The real depth value of the nearest  pixel. 0: Left view.  1: Right view
  double Zfar[2];           //!> The real depth value of the farthest pixel. 0: Left view.  1: Right view
#endif
  imgpel DepthThreshold;    //!> only used for Merging option 2
  int    HoleCountThreshold;//!> only used for Merging option 2

#if VSP_OPTIMIZATION
  int  SynDirection;
  int  WeightLeft;
  int   WeightRight;
  int  WeightLeftTable[PIXEL_VALUE_RANGE];
  int  WeightRightTable[PIXEL_VALUE_RANGE];
  DisparityTable  DisparityLookupTable[2][PIXEL_VALUE_RANGE];
 // DisparityTable  DisparityRightTable[PIXEL_VALUE_RANGE];
#else
  double WeightLeft;   //!> Weighting factor for left  view in blending
  double WeightRight;  //!> Weighting factor for right view in blending
#endif
  
  imgpel** RefView[2][3];  //!> The upsampled version of the ref view   0 -> Left(Y,U,V);   1 -> Right(Y,U,V);
  imgpel** RefDepth[2];    //!> The upsampled version of the ref depth  0 -> Left(Y,U,V);   1 -> Right(Y,U,V);
  
  //Zhejiang
  int FrameNumber;                  //which frame is being processed
  int WarpToRight;                  //1:warp direction is to the right side; 0: to the left side
  int CountHOLEFILLPIXEL;           //debug using
  int Maxdk, Mindk, Maxz, Minz;     //max and min value in current frame
  int SplattingDepthThreshold;      //determine which area can be regard as background
  int TemporalImprovementOption;    //0: Off; 1: On;
  int WarpEnhancementOption;
  int CleanNoiseOption;             //0: off; 1: On
  imgpel** RefViewLast[2];          //used in TIM: 0->Left; 1->Right
  imgpel** RefDepthLast[2];         //used in TIM: 0->Left; 1->Right

  bool MemAllocated;


  byte** Dmap[5];             //!> Store the depth levels  0 -> Left;   1 -> Right;    2 -> Merged;  3->After hole filling; 4:after downsampling
  byte** Mask[3];             //!> Used for temporary mask  0 -> Left;   1 -> Right;    2 -> Merged;
  byte** BoundaryMask[2];     //!> Used to indicate boudary positions  0 -> Left;   1 -> Right. 255 -> boundary pixel

  imgpel** SynY[5];           //!> Y. 0 -> Left; 1 -> Right;  2 -> Merged    3 -> After hole filling; 4:after downsampling
  imgpel** SynU[5];           //!> Upsampled UV. 0 -> Left;   1 -> Right;    2 -> Merged;    3 -> After hole filling; 4:after downsampling
  imgpel** SynV[5];           //!> Upsampled UV. 0 -> Left;   1 -> Right;    2 -> Merged;    3 -> After hole filling; 4:after downsampling

#if POZNAN_NONLINEAR_DEPTH
  imgpel nonlinear_depth_lut_forward[NONLINEAR_DEPTH_LUT_SIZE];
  imgpel nonlinear_depth_lut_backward[NONLINEAR_DEPTH_LUT_SIZE];
#endif

#if NTT_SUBPEL_VSP_M24796
	int PixelValueMul20[PIXEL_VALUE_RANGE];
	int PiXelValueMul5[PIXEL_VALUE_RANGE];
#endif

private:
#if ZJU_VSP
  void ViewGen_1LWH_splatting(int ViewId);
#if QC_VSP_Asymmetric_Resolution
  void ViewGen_1LWH_splatting420(int ViewId);
#endif


#if BOUNDARY_DETECT_ATM02
	void DetectBoundary( byte** edge, imgpel** depth, int width, int height, int threshold);
#endif

#endif
#if QCOM_VSP 
  void ViewGen_1LWH(int ViewId);
#if QC_VSP_Asymmetric_Resolution
  void ViewGen_1LWH420(int ViewId);
  void TemporalImprovementMethod420( imgpel**ImageCur, imgpel **ImageLast, imgpel **DepthCur, imgpel **DepthLast,
					                        int frame, int Width, int Height );
  void FindDepthMaxMin420( imgpel** map, int ViewID);
#endif
#else
  void PixelMapping(int x, int y, byte d, float z, 
	  imgpel** RefY, imgpel** RefU, imgpel** RefV, 
	  int ViewId, double dk, int flooring);
  void PixelMapping(int x,byte d, imgpel* mask,imgpel* bounday,
	  imgpel* ref_Y,imgpel* ref_U,imgpel* ref_V,imgpel* ref_d,
	  imgpel* syn_Y,imgpel*syn_U,imgpel* syn_V,
	  int view_id,double dk,int flooring, int first_map);
  void ForwardWarp();
  void ForwardWarpSingleView(int ViewId);
  void Merge();
  void FillHoles(imgpel** Yo, imgpel** Yi);
  void FillHoles();
  int  IsBackgroundOnRight(int xleft, int xright, int y, int blksize);
  void DetectBoundary( byte** edge, imgpel** depth, int width, int height, int threshold);
  bool IsBoundary(byte** BoundaryArray, int x, int y);
  int  CountHolePixels(byte** MaskMap, int x, int y, int width);
#endif
  void ScaleDownSyn(imgpel** Yo, imgpel** Yi);
  
  
  int  DownsampleView(imgpel** Yo, imgpel** Yi, int Width, int Height, int Factor);
  void DoDownsample(imgpel** Yo, imgpel** Yi, int Width, int Height);
  
  //Zhejiang Univ., new functions
  void FindDepthMaxMin( imgpel** map, int ViewID);
  void TemporalImprovementMethod( imgpel**ImageCur, imgpel **ImageLast, imgpel **DepthCur, imgpel **DepthLast,
					                        int frame, int Width, int Height );

  
public:

  CViewInterpolation1D();
  ~CViewInterpolation1D();

#if NOKIA_DISP_CALC_B0150
  int InitViewInterpolation1D(ViewSynParams* pViewSynParams);
#else
  int InitViewInterpolation1D(ViewSynParams* pViewSynParams,CameraParameters* pCamParams);
#endif
  //int UpdataCamParams(CamParaUpdate* pNewCamParams);

  void  FreeMem();

#if POZNAN_NONLINEAR_DEPTH
  void SetNonLinearDepth(int nonlinear_depth_num, char nonlinear_depth_points[256]);
#endif
  void SetWidth (int sWidth ) { Width  = sWidth;  }
  void SetHeight(int sHeight) { Height = sHeight; }
  void SetFrameNumber(int sFrameNumber) { FrameNumber = sFrameNumber; } //Zhejiang
#if NOKIA_DISP_CALC_B0150
  void SetDisparityLUTL(int** disparity_lut_left) { DisparityLUTL = disparity_lut_left; }
  void SetDisparityLUTR(int** disparity_lut_right) { DisparityLUTR = disparity_lut_right; }
#else
  void SetFocalLength(double sFocalLength) { FocalLength = sFocalLength; }
  void SetLTranslationLeft(double sLTranslationLeft) { LTranslation[LEFTVIEW] = sLTranslationLeft; }
  void SetLTranslationRight(double sLTranslationRight) { LTranslation[RGHTVIEW] = sLTranslationRight; }
  void SetduPrincipalLeft(double sduPrincipalLeft) { duPrincipal[LEFTVIEW] = sduPrincipalLeft; }
  void SetduPrincipalRight(double sduPrincipalRight) { duPrincipal[RGHTVIEW] = sduPrincipalRight; }
  void SetZnearL(double sZnearL) { Znear[LEFTVIEW] = sZnearL; }
  void SetZfarL(double sZfarL) { Zfar[LEFTVIEW] = sZfarL; }
  void SetZnearR(double sZnearR) { Znear[RGHTVIEW] = sZnearR; }
  void SetZfarR(double sZfarR) { Zfar[RGHTVIEW] = sZfarR; }
#endif
  void SetSubPelOption(int sSubPelOption);
  void SetSplattingOption(int sSplattingOption) { SplattingOption = sSplattingOption; }
  void SetUpsampleRefs(int sUpsampleRefs) { UpsampleRefs = sUpsampleRefs; }
  void SetMergingOption(int sMergingOption)  { MergingOption = sMergingOption; } 
  void SetDepthThreshold(int sDepthThreshold) { DepthThreshold = (imgpel)sDepthThreshold; }
  void SetHoleCountThreshold(int sHoldCountThreshold) { HoleCountThreshold = sHoldCountThreshold; }
  void SetBoundaryGrowth(int sBoundaryGrowth) { BoundaryGrowth = sBoundaryGrowth; }
  void SetTemporalImprovementOption(int sTemporalImprovementOption) { TemporalImprovementOption = sTemporalImprovementOption;} //Zhejiang, May 4
  void SetWarpEnhancementOption(int sWarpEnhancementOption) { WarpEnhancementOption = sWarpEnhancementOption; }
  void SetCleanNoiseOption(int sCleanNoiseOption) { CleanNoiseOption = sCleanNoiseOption;}
 
#if QC_VSP_Asymmetric_Resolution
  int  AllocMem( Boolean bMixedRes);   //!> Must be called after the resolution is set
  int  DoOneFrame(ViewSynIOFrmData* pVSIOFrmData, Boolean bMixedRes);
#else
  int  AllocMem();   //!> Must be called after the resolution is set
  int DoOneFrame(ViewSynIOFrmData* pVSIOFrmData);
#endif
  int  DoOneFrame(imgpel*** RefLeft, imgpel*** RefRight, 
	  imgpel** RefDepthLeft, imgpel** RefDepthRight,
	  imgpel*** Syn,
	  int outputPrecision,
	  int outputItem);
  byte** GetSynMaskPointer() { return Mask[MERGVIEW]; }
  byte** GetSynDepthPointer() { return Dmap[MERGVIEW]; }
  
  imgpel** GetSynColorLeftY () { return SynY[LEFTVIEW]; }
  imgpel** GetSynColorRightY() { return SynY[RGHTVIEW]; }
  imgpel** GetSynColorLeftU () { return SynU[LEFTVIEW]; }
  imgpel** GetSynColorRightU() { return SynU[RGHTVIEW]; }
  imgpel** GetSynColorLeftV () { return SynV[LEFTVIEW]; }
  imgpel** GetSynColorRightV() { return SynV[RGHTVIEW]; }
  imgpel** GetSynDepthLeft ()  { return Dmap[LEFTVIEW]; }
  imgpel** GetSynDepthRight()  { return Dmap[RGHTVIEW]; } 
};

extern CViewInterpolation1D ViewSyn1DMode;
#endif
