/* 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.
 */


/*!
 *************************************************************************************
 * \file mc_depth_prediction.c
 *
 * \brief
 *    interpolate the 1/4-pixel accurate depth map with bi-linear filter 
 *
 * \author
 *      - Wenyi Su         <suwy@mail.ustc.edu.cn>
 *      - Dmytro           <Dmytro.Rusanovskyy@nokia.com>
 *
 *************************************************************************************
*/

#include "global.h"
#include "mc_depth_prediction.h"

/*!
************************************************************************
* \brief
*    Integer positions
************************************************************************
*/ 
static void get_depth_block_00(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos )
{
	// fastest to just move an entire block, since block is a temp block is a 256 byte block (16x16)
	// writes 2 lines of 16 imgpel 1 to 8 times depending in ver_block_size
	int j;
	imgpel *orig_line,*cur_line;

	for (j = 0; j < ver_block_size; ++j)
	{ 
		cur_line=&(cur_imgY[j][x_pos]);
		orig_line=block[j];
		memcpy(orig_line,cur_line,hor_block_size*sizeof(imgpel));
	}
}


/*!
************************************************************************
* \brief
*    Qpel (1,0) horizontal
************************************************************************
*/ 
static void get_depth_luma_10(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos , int max_imgpel_value)
{
	imgpel *p0, *p1;
	imgpel *orig_line;
	int i, j;
	int result;

	for (j = 0; j < ver_block_size; ++j)
	{
		p0 = &cur_imgY[j][x_pos];
		p1 = p0 + 1;

		orig_line = block[j];            

		for (i = 0; i < hor_block_size; ++i)
		{  

			result  = 3*(*p0++) +(*p1++);
			*orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 2)>>2));
			orig_line++;
		}
	}
}

/*!
************************************************************************
* \brief
*    Half horizontal
************************************************************************
*/ 
static void get_depth_luma_20(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos , int max_imgpel_value)
{
	imgpel *p0, *p1;
	imgpel *orig_line;
	int i, j;
	int result;
	for (j = 0; j < ver_block_size; j++)
	{
		p0 = &cur_imgY[j][x_pos];
		p1 = p0 + 1;
		orig_line = block[j];

		for (i = 0; i < hor_block_size; i++)
		{        
			result  = *(p0++) + *(p1++);

			*orig_line++ = (imgpel) iClip1(max_imgpel_value, ((result + 1)>>1));
		}
	}
}

/*!
************************************************************************
* \brief
*    Qpel (3,0) horizontal
************************************************************************
*/ 
static void get_depth_luma_30(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos , int max_imgpel_value)
{
	imgpel *p0, *p1;
	imgpel *orig_line;
	int i, j;
	int result;

	for (j = 0; j < ver_block_size; j++)
	{
		p0 = &cur_imgY[j][x_pos];
		p1 = p0 + 1;

		orig_line = block[j];            

		for (i = 0; i < hor_block_size; i++)
		{        
			result  = *(p0++) + 3*(*(p1++)) ;

			*orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 2)>>2));
			orig_line++;
		}
	}
}

/*!
************************************************************************
* \brief
*    Qpel vertical (0, 1)
************************************************************************
*/ 
static void get_depth_luma_01(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos, int shift_x, int max_imgpel_value)
{
	imgpel *p0, *p1;
	imgpel *orig_line; // *cur_line;
	int i, j;
	int result;
	//int jj = 0;
	p0 = &(cur_imgY[0][x_pos]);
	for (j = 0; j < ver_block_size; j++)
	{                  
		p1 = p0 + shift_x;          

		orig_line = block[j];
		//cur_line = &(cur_imgY[jj++][x_pos]);

		for (i = 0; i < hor_block_size; i++)
		{
			result  = 3*(*(p0++)) + *(p1++);

			*orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 2)>>2));
			orig_line++;
		}
		p0 = p1 - hor_block_size;
	}
}


/*!
************************************************************************
* \brief
*    Half vertical
************************************************************************
*/ 
static void get_depth_luma_02(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos, int shift_x, int max_imgpel_value)
{
	imgpel *p0, *p1;
	imgpel *orig_line;
	int i, j;
	int result;
	p0 = &(cur_imgY[ 0][x_pos]);
	for (j = 0; j < ver_block_size; j++)
	{                  
		p1 = p0 + shift_x;          
		orig_line = block[j];

		for (i = 0; i < hor_block_size; i++)
		{
			result  = *(p0++) + *(p1++);

			*orig_line++ = (imgpel) iClip1(max_imgpel_value, ((result + 1)>>1));
		}
		p0 = p1 - hor_block_size;
	}
}


/*!
************************************************************************
* \brief
*    Qpel vertical (0, 3)
************************************************************************
*/ 
static void get_depth_luma_03(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos, int shift_x, int max_imgpel_value)
{
	imgpel *p0, *p1;
	imgpel *orig_line;
	int i, j;
	int result;

	p0 = &(cur_imgY[ 0][x_pos]);
	for (j = 0; j < ver_block_size; j++)
	{                  
		p1 = p0 + shift_x;          

		orig_line = block[j];

		for (i = 0; i < hor_block_size; i++)
		{
			result  = *(p0++) + 3*(*(p1++)) ;

			*orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 2)>>2));
			orig_line++;
		}
		p0 = p1 - hor_block_size;
	}
}

/*!
************************************************************************
* \brief
*    Hpel horizontal, Qpel vertical (2, 1)
************************************************************************
*/ 
static void get_depth_luma_21(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos, int max_imgpel_value)
{
	int i, j;
	/* Vertical & horizontal interpolation */
	imgpel *p0, *p1, *p2, *p3;
	imgpel *orig_line;  
	int result;      


	for(j=0;j<ver_block_size;++j)
	{
		p0=&cur_imgY[j][x_pos];
		p1=&cur_imgY[j+1][x_pos];
		p2=p0+1;
		p3=p1+1;

		orig_line = block[j];
		for(i=0;i<hor_block_size;++i)
		{
			result=3*(*(p0++)+*(p1++))+*(p2++)+*(p3++);
			*orig_line=(imgpel) iClip1(max_imgpel_value, ((result + 4)>>3));
			orig_line++;
		}
	}

}

/*!
************************************************************************
* \brief
*    Hpel horizontal, Hpel vertical (2, 2)
************************************************************************
*/ 
static void get_depth_luma_22(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos, int max_imgpel_value)
{
	int i, j;
	/* Vertical & horizontal interpolation */
	imgpel *p0, *p1, *p2, *p3;
	imgpel *orig_line;  
	int result;      


	for(j=0;j<ver_block_size;++j)
	{
		p0=&cur_imgY[j][x_pos];
		p1=&cur_imgY[j+1][x_pos];
		p2=p0+1;
		p3=p1+1;

		orig_line = block[j];
		for(i=0;i<hor_block_size;++i)
		{
			result=*(p0++)+*(p1++)+*(p2++)+*(p3++);
			*orig_line=(imgpel) iClip1(max_imgpel_value, ((result + 2)>>2));
			orig_line++;
		}
	}
}

/*!
************************************************************************
* \brief
*    Hpel horizontal, Qpel vertical (2, 3)
************************************************************************
*/ 
static void get_depth_luma_23(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos, int max_imgpel_value)
{
	int i, j;
	/* Vertical & horizontal interpolation */
	imgpel *p0, *p1, *p2, *p3;
	imgpel *orig_line;  
	int result;      


	for(j=0;j<ver_block_size;++j)
	{
		p0=&cur_imgY[j][x_pos];
		p1=&cur_imgY[j+1][x_pos];
		p2=p0+1;
		p3=p1+1;

		orig_line = block[j];
		for(i=0;i<hor_block_size;++i)
		{
			result=*(p0++)+*(p1++)+3*(*(p2++)+*(p3++));
			*orig_line=(imgpel) iClip1(max_imgpel_value, ((result + 4)>>3));
			orig_line++;
		}
	}
}

/*!
************************************************************************
* \brief
*    Qpel horizontal, Hpel vertical (1, 2)
************************************************************************
*/ 
static void get_depth_luma_12(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos, int shift_x, int max_imgpel_value)
{
	int i, j;
	/* Vertical & horizontal interpolation */
	imgpel *p0, *p1, *p2, *p3;
	imgpel *orig_line;  
	int result;      

	UNREFERENCED_PARAMETER(shift_x);

	for(j=0;j<ver_block_size;++j)
	{
		p0=&cur_imgY[j][x_pos];
		p1=&cur_imgY[j+1][x_pos];
		p2=p0+1;
		p3=p1+1;

		orig_line = block[j];
		for(i=0;i<hor_block_size;++i)
		{
			result=3*(*(p0++)+*(p2++))+*(p1++)+*(p3++);
			*orig_line=(imgpel) iClip1(max_imgpel_value, ((result + 4)>>3));
			orig_line++;
		}
	}
}


/*!
************************************************************************
* \brief
*    Qpel horizontal, Hpel vertical (3, 2)
************************************************************************
*/ 
static void get_depth_luma_32(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos, int shift_x, int max_imgpel_value)
{
	int i, j;
	/* Vertical & horizontal interpolation */
	imgpel *p0, *p1, *p2, *p3;
	imgpel *orig_line;  
	int result;      

	UNREFERENCED_PARAMETER(shift_x);

	for(j=0;j<ver_block_size;++j)
	{
		p0=&cur_imgY[j][x_pos];
		p1=&cur_imgY[j+1][x_pos];
		p2=p0+1;
		p3=p1+1;

		orig_line = block[j];
		for(i=0;i<hor_block_size;++i)
		{
			result=3*(*(p1++)+*(p3++))+*(p0++)+*(p2++);
			*orig_line=(imgpel) iClip1(max_imgpel_value, ((result + 4)>>3));
			orig_line++;
		}
	}
}

/*!
************************************************************************
* \brief
*    Qpel horizontal, Qpel vertical (3, 3)
************************************************************************
*/ 
static void get_depth_luma_33(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos, int shift_x, int max_imgpel_value)
{
	int i, j;
	/* Vertical & horizontal interpolation */
	imgpel *p0, *p1, *p2, *p3;
	imgpel *orig_line;  
	int result;      

	UNREFERENCED_PARAMETER(shift_x);

	for(j=0;j<ver_block_size;++j)
	{
		p0=&cur_imgY[j][x_pos];
		p1=&cur_imgY[j+1][x_pos];
		p2=p0+1;
		p3=p1+1;

		orig_line = block[j];
		for(i=0;i<hor_block_size;++i)
		{
			result=*(p1++)+*(p2++)+2*(*(p3++));
			*orig_line=(imgpel) iClip1(max_imgpel_value, ((result + 2)>>2));
			orig_line++;
		}
	}
}



/*!
************************************************************************
* \brief
*    Qpel horizontal, Qpel vertical (1, 1)
************************************************************************
*/ 
static void get_depth_luma_11(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos, int shift_x, int max_imgpel_value)
{
	int i, j;
	/* Vertical & horizontal interpolation */
	imgpel *p0, *p1, *p2; //, *p3;
	imgpel *orig_line;  
	int result;      

	UNREFERENCED_PARAMETER(shift_x);

	for(j=0;j<ver_block_size;++j)
	{
		p0=&cur_imgY[j][x_pos];
		p1=&cur_imgY[j+1][x_pos];
		p2=p0+1;
		//p3=p1+1;

		orig_line = block[j];
		for(i=0;i<hor_block_size;++i)
		{
			result=2*(*(p0++))+*(p1++)+*(p2++);
			*orig_line=(imgpel) iClip1(max_imgpel_value, ((result + 2)>>2));
			orig_line++;
		}
	}
}

/*!
************************************************************************
* \brief
*    Qpel horizontal, Qpel vertical (1, 3)
************************************************************************
*/ 
static void get_depth_luma_13(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos, int shift_x, int max_imgpel_value)
{
	int i, j;
	/* Vertical & horizontal interpolation */
	imgpel *p0, *p1, *p2, *p3;
	imgpel *orig_line;  
	int result;      

	UNREFERENCED_PARAMETER(shift_x);

	for(j=0;j<ver_block_size;++j)
	{
		p0=&cur_imgY[j][x_pos];
		p1=&cur_imgY[j+1][x_pos];
		p2=p0+1;
		p3=p1+1;

		orig_line = block[j];
		for(i=0;i<hor_block_size;++i)
		{
			result=*(p0++)+*(p3++)+2*(*(p2++));
			*orig_line=(imgpel) iClip1(max_imgpel_value, ((result + 2)>>2));
			orig_line++;
		}
	}
}

/*!
************************************************************************
* \brief
*    Qpel horizontal, Qpel vertical (3, 1)
************************************************************************
*/ 
static void get_depth_luma_31(imgpel **block, imgpel **cur_imgY, int ver_block_size, int hor_block_size, int x_pos, int shift_x, int max_imgpel_value)
{
	int i, j;
	/* Vertical & horizontal interpolation */
	imgpel *p0, *p1, *p2; // *p3;
	imgpel *orig_line;  
	int result;      

	UNREFERENCED_PARAMETER(shift_x);

	for(j=0;j<ver_block_size;++j)
	{
		p0=&cur_imgY[j][x_pos];
		p1=&cur_imgY[j+1][x_pos];
		p2=p0+1;
		//p3=p1+1;

		orig_line = block[j];
		for(i=0;i<hor_block_size;++i)
		{
			result=*(p0++)+*(p2++)+2*(*(p1++));
			*orig_line=(imgpel) iClip1(max_imgpel_value, ((result + 2)>>2));
			orig_line++;
		}
	}
}



/*!
 ************************************************************************
 * \brief
 *    Interpolation of 1/4 subpixel with bi-linear interpolation
 ************************************************************************
 */ 
void get_depth_mc_luma(imgpel** img_ref_Y, int x_pos, int y_pos, int hor_block_size, int ver_block_size, imgpel **block,
					int shift_x, int max_x, int max_y, int max_imgpel_value)
{
#if NOKIA_USTC_B_VSP_M26069
  const int int_pel_dis=1;
  int dx=0,dy=0;
#else
  int dx = (x_pos & 3);
  int dy = (y_pos & 3);
#if D_MVP_MODE
  const int int_pel_dis=1;
  x_pos=((x_pos+2) >>2);
  y_pos=((y_pos +2)>> 2);
#else
  x_pos >>= 2;
  y_pos >>= 2;
#endif //#if D_MVP_MODE
#endif//#if NOKIA_USTC_B_VSP_M26069

	x_pos = iClip3(-18, max_x+2, x_pos);
	y_pos = iClip3(-10, max_y+2, y_pos);

#if D_MVP_MODE
	if ((dx == 0 && dy == 0)||(int_pel_dis))
#else
	if (dx == 0 && dy == 0)
#endif
	{
		get_depth_block_00(block, &img_ref_Y[y_pos], ver_block_size, hor_block_size,x_pos);
	}
	else
	{ /* other positions */
		if (dy == 0) /* No vertical interpolation */
		{         
			if (dx == 1)
				get_depth_luma_10(block, &img_ref_Y[ y_pos], ver_block_size, hor_block_size, x_pos, max_imgpel_value);
			else if (dx == 2)
				get_depth_luma_20(block, &img_ref_Y[ y_pos], ver_block_size, hor_block_size, x_pos, max_imgpel_value);
			else
				get_depth_luma_30(block, &img_ref_Y[ y_pos], ver_block_size, hor_block_size, x_pos, max_imgpel_value);
		}
		else if (dx == 0) /* No horizontal interpolation */        
		{         
			if (dy == 1)
				get_depth_luma_01(block, &img_ref_Y[y_pos], ver_block_size, hor_block_size, x_pos, shift_x, max_imgpel_value);
			else if (dy == 2)
				get_depth_luma_02(block, &img_ref_Y[ y_pos], ver_block_size, hor_block_size, x_pos, shift_x, max_imgpel_value);
			else
				get_depth_luma_03(block, &img_ref_Y[ y_pos], ver_block_size, hor_block_size, x_pos, shift_x, max_imgpel_value);
		}
		else if (dx == 2)  /* Vertical & horizontal interpolation */
		{  
			if (dy == 1)
				get_depth_luma_21(block, &img_ref_Y[ y_pos], ver_block_size, hor_block_size, x_pos, max_imgpel_value);
			else if (dy == 2)
				get_depth_luma_22(block, &img_ref_Y[ y_pos], ver_block_size, hor_block_size, x_pos, max_imgpel_value);
			else
				get_depth_luma_23(block, &img_ref_Y[ y_pos], ver_block_size, hor_block_size, x_pos, max_imgpel_value);
		}
		else if (dy == 2)
		{
			if (dx == 1)
				get_depth_luma_12(block, &img_ref_Y[ y_pos], ver_block_size, hor_block_size, x_pos, shift_x, max_imgpel_value);
			else
				get_depth_luma_32(block, &img_ref_Y[ y_pos], ver_block_size, hor_block_size, x_pos, shift_x, max_imgpel_value);
		}
		else
		{
			if (dx == 1)
			{
				if (dy == 1)
					get_depth_luma_11(block, &img_ref_Y[ y_pos], ver_block_size, hor_block_size, x_pos, shift_x, max_imgpel_value);
				else
					get_depth_luma_13(block, &img_ref_Y[ y_pos], ver_block_size, hor_block_size, x_pos, shift_x, max_imgpel_value);
			}
			else
			{
				if (dy == 1)
					get_depth_luma_31(block, &img_ref_Y[ y_pos], ver_block_size, hor_block_size, x_pos, shift_x, max_imgpel_value);
				else
					get_depth_luma_33(block, &img_ref_Y[ y_pos], ver_block_size, hor_block_size, x_pos, shift_x, max_imgpel_value);
			}
		}
	}
}

