/*Daala video codec
Copyright (c) 2006-2013 Daala project contributors.  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.

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

#if !defined(_mc_H)
# define _mc_H (1)

typedef struct od_mv_grid_pt od_mv_grid_pt;

# include "state.h"

/*Interpolation along an edge by interpolating vectors.*/
# define OD_MC_INTERP_VECTOR (1)
/*Interpolation along an edge by blending samples from different vectors.*/
# define OD_MC_INTERP_BLEND (0)

# define od_mc_interp_type(a, b, c, d) \
  ((a) | ((b) << 1) | ((c) << 2) | ((d) << 3))

# define OD_MC_INTERP_BBBB (0)
# define OD_MC_INTERP_VBBB (1)
# define OD_MC_INTERP_BVBB (2)
# define OD_MC_INTERP_VVBB (3)
# define OD_MC_INTERP_BBVB (4)
# define OD_MC_INTERP_VBVB (5)
# define OD_MC_INTERP_BVVB (6)
# define OD_MC_INTERP_VVVB (7)
# define OD_MC_INTERP_BBBV (8)
# define OD_MC_INTERP_VBBV (9)
# define OD_MC_INTERP_BVBV (10)
# define OD_MC_INTERP_VVBV (11)
# define OD_MC_INTERP_BBVV (12)
# define OD_MC_INTERP_VBVV (13)
# define OD_MC_INTERP_BVVV (14)
# define OD_MC_INTERP_VVVV (15)

/*Indexing of vetices and edges:
  0--0--1
  |     |
  3     1
  |     |
  3--2--2

  Interpolation formulas:
  i = horizontal position in the destination block, 0...blk_sz - 1
  j = vertical position  in the destination block, 0...blk_sz - 1
  blk_sz = length of an edge in the destination block in pixels
  blk_sz2 = blk_sz*blk_sz
  w[k] = bilinear VECTOR weight of vertex k:
  w[0] = (blk_sz - i)*(blk_sz - j)/blk_sz2
  w[1] = i*(blk_sz - j)/blk_sz2
  w[2] = i*j/blk_sz2
  w[3] = (blk_sz - i)*j/blk_sz2
  u[k] = bilinear weight of edge k:
  u[0] = (blk_sz - j)/blk_sz
  u[1] = i/blk_sz
  u[2] = j/blk_sz
  u[3] = (blk_sz - i)/blk_sz
  s[k] = bilinear weight of vertex k:
  m[k] = motion vector k
  sw[k, oc] = BLEND weight of vertex k in a split block with outside corner oc:
  sw[oc + 0, oc] = w[oc] + w[oc + 1]/2 + w[oc + 3]/2
  sw[oc + 1, oc] = w[oc + 1]/2
  sw[oc + 2, oc] = w[oc + 2]
  sw[oc + 3, oc] = w[oc + 3]/2
  src[m] = source image value of pixel (i, j) offset by the given motion
   vector, bilinearly interpolated from the values at half-pel locations.
  First, horizontal interpolation is done, and the result is truncated to
   an integer, followed by vertical interpolation and truncation to an
   integer.

  Blending and interpolation functions are defined by the type of edges:
  V: vector interpolation edge.
     Along this edge, the motion vector is linearly interpolated from the
      value at one vertex to the other.
  B: blend edge
     Along this edge, the predicted value is linearly interpolated between
      that of the source image offset by the motion vector at one vertex
      to the value of the source image offset by the motion vector at the
      other vertex.
  This allows for C^0 switching between overlapped block motion compensation
   and smooth, per-pixel motion vector fields.
  The various interpolation formulas below are chosen so that:
   1) They have the proper form along each edge,
   2) They still match each other when a block is split to add a new motion
       vector in the middle (subject to the modifications to the blending
       weights listed above).
   2) All the vectors can be computed with simple bilinear interpolation,
   3) All the resulting source image pixels can be blended with simple
       bilinear interpolation.

  There are 6 similar classes of edge configurations:

  VVVV:
    src[m[0]*w[0] + m[1]*w[1] + m[2]*w[2] + m[3]*w[3]]
  BVVV (and rotations thereof):
    src[u[0]*m[0] + w[2]*m[2] + w[3]*m[3]]*w[0]
     + src[u[0]*m[1] + w[2]*m[2] + w[3]*m[3]]*w[1]
     + src[m[0]*w[0] + m[1]*w[1] + m[2]*w[2] + m[3]*w[3]]*u[2]
  BVBV (and rotation thereof):
    src[u[0]*m[0] + u[3]*m[2]]*u[2]
     + src[u[0]*m[1] + u[3]*m[3]]*u[1]
  VVBB (and rotations thereof):
    src[(w[0] + u[2])*m[0] + w[1]*m[1]]*w[0]
     + src[w[0]*m[0] + w[1]*m[1] + w[2]*m[2] + w[3]*m[3]]*w[1]
     + src[w[1]*m[1] + (w[2] + u[3])*m[2]]*w[2]
     + src[m[3]]*w[3]
  VBBB (and rotations thereof):
    src[(u[3] + w[2])*m[0] + w[1]*m[1]]*w[0]
     + src[w[0]*m[0] + (w[1] + u[2])*m[1]]*w[1]
     + src[m[2]]*w[2] + src[m[3]]*w[3]
  BBBB:
     src[m[0]]*w[0] + src[m[1]]*w[1] + src[m[2]]*w[2] + src[m[3]]*w[3]

  The remaining 10 edge configurations can be obtained by rotations of these
   formulas.

  Lots of indexing and finite differences where tiny errors may be made here.
  This is also a good candidate for SIMD optimization.
  Each case can be optimized separately.
  The first and last are expected to be more common than the others.*/

/*We very intentionally do NOT use the quadtree data structure proposed by
   Balmelli, as it is encumbered by patents.
  Fortunately, our relatively limited levels of subdivision makes it mostly
   unnecessary.*/
struct od_mv_grid_pt {
  /*The x, y offsets of the motion vector in units of 1/8th pixels.*/
  int mv[2];
  /*Whether or not this MV actually has a valid value.*/
  unsigned valid:1;
};

void od_mc_setup_mvc(ogg_int32_t dmv[4], const ogg_int32_t mvs[4],
 const int m[4], int r, int log_xblk_sz, int log_yblk_sz);
void od_mc_predict8(od_state *state, unsigned char *dst, int dystride,
 const unsigned char *src, int systride, const ogg_int32_t mvx[4],
 const ogg_int32_t mvy[4], int oc, int s, int log_xblk_sz, int log_yblk_sz);
void od_state_mvs_clear(od_state *state);
void od_state_get_predictor(od_state *state, int pred[2],
 int vx, int vy, int level, int mv_res);
int od_mv_level1_prob(od_mv_grid_pt **grid, int vx, int vy);

#endif
