/******************************************************************************
 *                                                                          
 * This software module was originally developed by 
 *
 *   Cecile Dufour (LEP / ACTS-MoMuSys)
 *   Frederic Dufaux (Digital Equipment Corp.)
 *
 * and edited by 
 *
 *   Yoshinori Suzuki (Hitachi, Ltd.)
 *   Yuichiro Nakaya (Hitachi, Ltd.)
 *
 *
 * in the course of development of the MPEG-4 Video (ISO/IEC 14496-2) standard.
 * This software module is an implementation of a part of one or more MPEG-4 
 * Video (ISO/IEC 14496-2) tools as specified by the MPEG-4 Video (ISO/IEC 
 * 14496-2) standard. 
 *
 * ISO/IEC gives users of the MPEG-4 Video (ISO/IEC 14496-2) standard free 
 * license to this software module or modifications thereof for use in hardware
 * or software products claiming conformance to the MPEG-4 Video (ISO/IEC 
 * 14496-2) standard. 
 *
 * Those intending to use this software module in hardware or software products
 * are advised that its use may infringe existing patents. The original 
 * developer of this software module and his/her company, the subsequent 
 * editors and their companies, and ISO/IEC have no liability for use of this 
 * software module or modifications thereof in an implementation. Copyright is 
 * not released for non MPEG-4 Video (ISO/IEC 14496-2) standard conforming 
 * products. 
 *
 * ACTS-MoMuSys partners retain full right to use the code for his/her own 
 * purpose, assign or donate the code to a third party and to inhibit third 
 * parties from using the code for non MPEG-4 Video (ISO/IEC 14496-2) standard
 * conforming products. This copyright notice must be included in all copies or
 * derivative works. 
 *
 * Copyright (c) 1997
 *
 *****************************************************************************/

/***********************************************************HeaderBegin*******
 *                                                                         
 * File:	sprite_util.c
 *
 * Author:	Frederic Dufaux, Cecile Dufour
 * Created:	06/20/96
 *                                                                         
 * Description: utilities for sprite encoding (STATIC/ DYNAMIC)
 * -- Compute_SpriteVop 
 * -- AddTraj
 * -- float_to_int
 * -- float_to_int2
 * -- PutSpritePieceInSprite
 * -- GetSpritePieceInSprite
 * -- PutSpritePieceInSprite2
 * -- GetSpritePieceInSprite2
 * -- MyFloatDiv 
 *			
 *
 * Notes: 	
 *
 * Modified: 15.11.97 Yoshinori Suzuki : modified Compute_SpriteVop. 
 *           15.11.97 Yuichiro Nakaya
 *                    Yoshinori Suzuki : added the following functions
 * -- StationalWarp 
 * -- TranslationalWarp 
 * -- FastAffineWarp 
 * -- PerspectiveWarp 
 * -- InterpolatePixelValue 
 * -- LinearExtrapolation 
 * -- FourSlashes 
 * -- FourSlashesShift 
 *
 ***********************************************************HeaderEnd*********/

/************************    INCLUDE FILES    ********************************/

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "sprite_util.h"
#include "vm_compos.h"
#include "mot_padding.h"

#include <math.h>

/***********************************************************CommentBegin******
 *
 * --    Compute_SpriteVop()
 *
 * Author : Yoshinori Suzuki : Hitachi, Ltd.
 *
 * Created : 15-11-97		
 *
 * Purpose :   main function for sprite warping
 * 
 * Arguments in :
 *
 * Arguments in / out :	
 *
 * Return values :	
 *  None
 * Side effects :	
 *
 *
 * Description :	
 *
 * See also :
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/

Void  Compute_SpriteVop(Vop *vop)
{
switch(GetVopNoOfSpritePoints(vop)) {
  case 0:
    StationalWarp(vop);
    break;
  case 1:
    TranslationalWarp(vop);
    break;
  case 2:
  case 3:
    FastAffineWarp(vop);
    break;
  case 4:
    PerspectiveWarp(vop);
    break;
}
}

/***********************************************************CommentBegin******
 *
 * --    StationalWarp()
 *
 * Author: Yoshinori Suzuki (Hitachi, Ltd.),
 *         Cecile Dufour (LEP/Philips France) and
 *         Frederic Dufaux (Digital Equipment Corp.)
 *
 * Created : 15-11-97	
 *
 * Purpose :  sprite warping using stationary transform
 * 
 * Arguments in : 
 *
 * Arguments in / out :	
 *
 * Return values :	
 *  None
 * Side effects :	
 *
 *
 * Description :	
 *
 * See also :
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/

Void StationalWarp(Vop *vop)
{
Vop *sprite;
Int width, widthc;
Int warp_width, warp_height;
Int warp_widthc, warp_heightc;
Int pel_warp, pel_in;
Int i,j;

SInt *dataYin, *dataUin, *dataVin, *dataAin;
SInt *dataYout, *dataUout, *dataVout, *dataAout;

sprite = GetVopSprite(vop);

SetConstantImage(vop->y_chan, 0);
SetConstantImage(vop->a_chan, 0);
SetConstantImage(vop->a_uv_chan, 0);
SetConstantImage(vop->u_chan, 0);
SetConstantImage(vop->v_chan, 0);

dataYin = (SInt *) GetImageData(GetVopY(sprite));
dataUin = (SInt *) GetImageData(GetVopU(sprite));
dataVin = (SInt *) GetImageData(GetVopV(sprite));
dataAin = (SInt *) GetImageData(GetVopA(sprite));

dataYout = (SInt *) GetImageData(GetVopY(vop));
dataUout = (SInt *) GetImageData(GetVopU(vop));
dataVout = (SInt *) GetImageData(GetVopV(vop));
dataAout = (SInt *) GetImageData(GetVopA(vop));

width = GetVopWidth(sprite);
warp_width = GetVopWidth(vop);
warp_height = GetVopHeight(vop);

widthc = width>>1;
warp_widthc = warp_width>>1;
warp_heightc = warp_height>>1;

for (j = 0; j < warp_height; j++) {
  for (i = 0; i < warp_width; i++) {
      pel_warp = j * warp_width + i;
      pel_in = j * width + i;
      dataYout[pel_warp] = dataYin[pel_in];
      dataAout[pel_warp] = dataAin[pel_in];
      }
    }

    /* chroma */
for (j = 0; j < warp_heightc; j++) {
  for (i = 0; i < warp_widthc; i++) {
      pel_warp = j * warp_widthc + i;
      pel_in = j * widthc + i;
      dataUout[pel_warp] = dataUin[pel_in];
      dataVout[pel_warp] = dataVin[pel_in];
      }
    }
SubsampleAlphaMap(GetVopA(vop),GetVopAuv(vop),GetVopShape(vop));
}

/***********************************************************CommentBegin******
 *
 * --    InterpolatePixelValue()
 *
 * Author : Yuichiro Nakaya : Hitachi, Ltd.
 *
 * Created : 14-11-97		
 *
 * Purpose :  interpolation of sample values 
 * 
 * Arguments in : 
 *
 * Arguments in / out :	
 *
 * Return values :	
 *  None
 * Side effects :	
 *
 *
 * Description :	
 *
 * See also :
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/

SInt InterpolatePixelValue(SInt *F, Int pos, Int width,
                           Int rx, Int ry, Int wpc, Int bias, Int pow_denom)
{
SInt *Fp;
Int rxc, ryc;
Int hstep, vstep;

Fp = F + pos;
rxc = wpc - rx;
ryc = wpc - ry;
hstep = rx ? 1 : 0;
vstep = ry ? width : 0;

return((SInt)(((ryc * (rxc * *Fp + rx * *(Fp+hstep))
                + ry * (rxc * *(Fp+vstep) + rx * *(Fp+vstep+hstep))) + bias)
              >> pow_denom));
}

/***********************************************************CommentBegin******
 *
 * --    TranslationalWarp()
 *
 * Author: Yoshinori Suzuki (Hitachi, Ltd.),
 *         Cecile Dufour (LEP/Philips France) and
 *         Frederic Dufaux (Digital Equipment Corp.)
 *
 * Created : 15-11-97	
 *
 * Purpose :  sprite warping using translational transform
 * 
 * Arguments in : 
 *
 * Arguments in / out :	
 *
 * Return values :	
 *  None
 * Side effects :	
 *
 *
 * Description :	
 *
 * See also :
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/

Void TranslationalWarp(Vop *vop)
{
Vop *sprite, *tmp_sprite=NULL;
Int no_of_sprite_points, warpingaccuracy;
Int width, height;
Int widthc, heightc;
Int warp_width, warp_height;
Int warp_widthc, warp_heightc;
Int left, top, hor_ref, ver_ref;
Int x0, y0;
Int x0p, y0p;
Int i,j;
Int pel_warp;
Int cxx, cyy, cxy, a, e, offset;
Int bias, sqr_wac;
Int rx, ry;
TrajPoint *tmp_refpoint;
TrajPoint *tmp_trajpoint;

Int warpprecision, warpmask;

SInt *dataYin, *dataUin, *dataVin, *dataAin;
SInt *dataYout, *dataUout, *dataVout, *dataAout, *dataAuvout;

sprite = GetVopSprite(vop);
tmp_sprite = CloneVop(sprite);
VopPadding(tmp_sprite);
PutVopShape(GetVopShape(sprite),vop);

no_of_sprite_points = GetVopNoOfSpritePoints(vop);
warpingaccuracy = GetVopWarpingAccuracy(vop) + 1;
warpprecision = 1 << warpingaccuracy;
warpmask = warpprecision - 1;
sqr_wac = warpingaccuracy << 1;
bias = 1 << (sqr_wac - 1);

SetConstantImage(vop->y_chan, 0);
SetConstantImage(vop->a_chan, 0);
SetConstantImage(vop->a_uv_chan, 0);
SetConstantImage(vop->u_chan, 0);
SetConstantImage(vop->v_chan, 0);

dataYin = (SInt *) GetImageData(GetVopY(tmp_sprite));
dataUin = (SInt *) GetImageData(GetVopU(tmp_sprite));
dataVin = (SInt *) GetImageData(GetVopV(tmp_sprite));
dataAin = (SInt *) GetImageData(GetVopA(tmp_sprite));

dataYout = (SInt *) GetImageData(GetVopY(vop));
dataUout = (SInt *) GetImageData(GetVopU(vop));
dataVout = (SInt *) GetImageData(GetVopV(vop));
dataAout = (SInt *) GetImageData(GetVopA(vop));
dataAuvout = (SInt *) GetImageData(GetVopAuv(vop));

width = GetVopWidth(tmp_sprite);
height = GetVopHeight(tmp_sprite);
left = 2*(GetVopSpriteLeftEdge(vop) - 16);
top  = 2*(GetVopSpriteTopEdge(vop)  - 16);

hor_ref = GetVopHorSpatRef(vop);
ver_ref = GetVopVerSpatRef(vop);

warp_width = GetVopWidth(vop);
warp_height = GetVopHeight(vop);

widthc = width>>1;
heightc = height>>1;
warp_widthc = warp_width>>1;
warp_heightc = warp_height>>1;

tmp_refpoint = GetVopRefPointCoord(vop);
tmp_trajpoint = GetVopTrajPointCoord(vop);
x0 = tmp_refpoint[0].x ;
y0 = tmp_refpoint[0].y ;
x0p = tmp_trajpoint[0].x + 2*x0 - left;
y0p = tmp_trajpoint[0].y + 2*y0 - top;

x0p = x0p << (warpingaccuracy-1);
y0p = y0p << (warpingaccuracy-1);

x0 -=  hor_ref;
y0 -=  ver_ref;

cxx = x0p;
cyy = y0p;
a = warpprecision;
e = warpprecision;

    /* luma & alpha */
for (j = 0; j < warp_height; cyy+=e, j++) {
  for (i = 0, cxx=x0p; i < warp_width; cxx+=a, i++) {
      pel_warp = j * warp_width + i;

      if (cxx<0||cyy<0||cxx>((width-1)<<warpingaccuracy)||
          cyy>((height-1)<<warpingaccuracy))
      {
           dataYout[pel_warp] = 0;
           if (GetVopShape(vop)==0) /* rectangular */
             dataAout[pel_warp] = 255;
           else
             if (GetVopShape(vop)==1||GetVopShape(vop)==2)
               dataAout[pel_warp] = 0;
      }
      else
      {

           offset = (cyy >> warpingaccuracy) * width + (cxx >> warpingaccuracy);
           rx = cxx & warpmask;
           ry = cyy & warpmask;

           if (GetVopShape(vop)==0) /* rectangular */
              dataAout[pel_warp] = 255;
           else
           {
              dataAout[pel_warp] = InterpolatePixelValue(dataAin, offset,
                                             width, rx, ry, warpprecision,
                                             bias, sqr_wac);
           }
           if(dataAout[pel_warp]>=128)
           {
              dataAout[pel_warp]=255;

              dataYout[pel_warp] = InterpolatePixelValue(dataYin, offset,
                                         width, rx, ry, warpprecision,
                                         bias, sqr_wac);
           }
           else dataAout[pel_warp]=0;

      }
  }
}

SubsampleAlphaMap(GetVopA(vop),GetVopAuv(vop),GetVopShape(vop));

cxx = cxy = (x0p + (x0p<0 ? 0 : 1)) >> 1;
cyy = (y0p + (y0p<0 ? 0 : 1)) >> 1;

    /* chroma */
for (j = 0; j < warp_heightc; cyy+=e, j++) {
  for  (i = 0, cxx=cxy; i < warp_widthc; cxx+=a, i++) {
      pel_warp = j * warp_widthc + i;

      if (cxx<0||cyy<0||cxx>((widthc-1)<<warpingaccuracy)||
          cyy>((heightc-1)<<warpingaccuracy))
      {
           dataUout[pel_warp] = 0;
           dataVout[pel_warp] = 0;
      }
      else
      {
      if(dataAuvout[pel_warp]>0) {

         offset = (cyy >> warpingaccuracy) * widthc + (cxx >> warpingaccuracy);
         rx = cxx & warpmask;
         ry = cyy & warpmask;

         dataUout[pel_warp] = InterpolatePixelValue(dataUin, offset,
                                            widthc, rx, ry, warpprecision,
                                            bias, sqr_wac);
         dataVout[pel_warp] = InterpolatePixelValue(dataVin, offset,
                                            widthc, rx, ry, warpprecision,
                                            bias, sqr_wac);
      }
      }
  }
}

FreeVop(tmp_sprite);
}

/***********************************************************CommentBegin******
 *
 * --    FastAffineWarp()
 *
 * Author: Yoshinori Suzuki (Hitachi, Ltd.),
 *         Yuichiro Nakaya (Hitachi, Ltd.),
 *         Cecile Dufour (LEP/Philips France) and
 *         Frederic Dufaux (Digital Equipment Corp.)
 *
 * Created : 15-11-97	
 *
 * Purpose : sprite warping using isotropic and affine transforms
 *           only requires the usage of 32-bit integer variables
 * 
 * Arguments in : 
 *
 * Arguments in / out :	
 *
 * Return values :	
 *  None
 * Side effects :	
 *
 *
 * Description :	
 *
 * See also :
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/

Void FastAffineWarp(Vop *vop)
{
Vop *sprite=NULL, *tmp_sprite=NULL;
Int no_of_sprite_points, warpingaccuracy;
Int width, height;
Int widthc, heightc;
Int warp_width, warp_height;
Int warp_widthc, warp_heightc;
Int left, top, hor_ref, ver_ref;
Int x0, y0, x1, y1, x2=0, y2=0;
Int x0p, y0p, x1p, y1p, x2p=0, y2p=0;
Int a, b, c, d, e, f;
Int a_i, a_f, b_i, b_f, d_i, d_f, e_i, e_f;
Int W, H=0, WH;
Int i, j;
Int pel_warp;
Int ex1p, ey1p, ex2p=0, ey2p=0;
Int VW, VH=0, VWH=0;
Int vw_pwr, vh_pwr=0, vwh_pwr=0;
Int r_pwr, r;
Int cxy, cyy, dnm_pwr, fracmask;
Int cxx_i, cxx_f, cyx_i, cyx_f, cxy_i, cxy_f, cyy_i, cyy_f, offset;
TrajPoint *tmp_refpoint;
TrajPoint *tmp_trajpoint;

Int rx, ry;
Int bias, sqr_wac;

Int warpprecision, warpmask;

SInt *dataYin, *dataUin, *dataVin, *dataAin;
SInt *dataYout, *dataUout, *dataVout, *dataAout, *dataAuvout;

sprite = GetVopSprite(vop);
tmp_sprite = CloneVop(sprite);
VopPadding(tmp_sprite);
PutVopShape(GetVopShape(sprite),vop);

no_of_sprite_points = GetVopNoOfSpritePoints(vop);
warpingaccuracy = GetVopWarpingAccuracy(vop) + 1;
warpprecision = 1 << warpingaccuracy;
warpmask = warpprecision - 1;
r_pwr = 4 - warpingaccuracy;
r = 1<<(4 - warpingaccuracy);
sqr_wac = warpingaccuracy << 1;
bias = 1 << (sqr_wac - 1);

SetConstantImage(vop->y_chan, 0);
SetConstantImage(vop->a_chan, 0);
SetConstantImage(vop->a_uv_chan, 0);
SetConstantImage(vop->u_chan, 0);
SetConstantImage(vop->v_chan, 0);

dataYin = (SInt *) GetImageData(GetVopY(tmp_sprite));
dataUin = (SInt *) GetImageData(GetVopU(tmp_sprite));
dataVin = (SInt *) GetImageData(GetVopV(tmp_sprite));
dataAin = (SInt *) GetImageData(GetVopA(tmp_sprite));

dataYout = (SInt *) GetImageData(GetVopY(vop));
dataUout = (SInt *) GetImageData(GetVopU(vop));
dataVout = (SInt *) GetImageData(GetVopV(vop));
dataAout = (SInt *) GetImageData(GetVopA(vop));
dataAuvout = (SInt *) GetImageData(GetVopAuv(vop));

width = GetVopWidth(tmp_sprite);
height = GetVopHeight(tmp_sprite);
left = 2*(GetVopSpriteLeftEdge(vop) - 16);
top  = 2*(GetVopSpriteTopEdge(vop)  - 16);

hor_ref = GetVopHorSpatRef(vop);
ver_ref = GetVopVerSpatRef(vop);warp_width = GetVopWidth(vop);
warp_height = GetVopHeight(vop);

widthc = width>>1;
heightc = height>>1;
warp_widthc = warp_width>>1;
warp_heightc = warp_height>>1;

tmp_refpoint = GetVopRefPointCoord(vop);
tmp_trajpoint = GetVopTrajPointCoord(vop);
x0 = tmp_refpoint[0].x ;
y0 = tmp_refpoint[0].y ;
x1 = tmp_refpoint[1].x ;
y1 = tmp_refpoint[1].y ;

x0p = tmp_trajpoint[0].x + 2*x0 ;
y0p = tmp_trajpoint[0].y + 2*y0 ;
x1p = tmp_trajpoint[1].x + 2*x1 ;
y1p = tmp_trajpoint[1].y + 2*y1 ;

x0 -=  hor_ref;
y0 -=  ver_ref;
x1 -=  hor_ref;
y1 -=  ver_ref;

x0p = x0p << 3;
y0p = y0p << 3;
x1p = x1p << 3;
y1p = y1p << 3;

if(no_of_sprite_points == 3) {
    x2 = tmp_refpoint[2].x;
    y2 = tmp_refpoint[2].y;

    x2p = tmp_trajpoint[2].x + 2*x2;
    y2p = tmp_trajpoint[2].y + 2*y2;

    x2 -= hor_ref;
    y2 -= ver_ref;

    x2p = x2p << 3;
    y2p = y2p << 3;
}

W = x1 - x0;

VW = 1; vw_pwr = 0;
while(VW < W) {
    VW <<= 1;
    vw_pwr++;
}

if(no_of_sprite_points == 3) {
    H = y2 - y0;
    WH = W*H;

    VH = 1; vh_pwr = 0;
    while(VH < H) {
         VH <<= 1;
         vh_pwr++;
     }
    VWH = VW * VH;
    vwh_pwr = vw_pwr + vh_pwr;
}

ex1p = LinearExtrapolation(x0, x1, x0p, x1p, W, VW) + ((x0+VW)<<4);
ey1p = LinearExtrapolation(y0, y1, y0p, y1p, W, VW) + (y0<<4);
if(no_of_sprite_points == 3) {
    ex2p = LinearExtrapolation(x0, x2, x0p, x2p, H, VH) + (x0<<4);
    ey2p = LinearExtrapolation(y0, y2, y0p, y2p, H, VH) + ((y0+VH)<<4);
}

x0p -= (left << 3);
y0p -= (top << 3);
x1p = ex1p - (left << 3);
y1p = ey1p - (top << 3);
if(no_of_sprite_points == 3) {
    x2p = ex2p - (left << 3);
    y2p = ey2p - (top << 3);
}

if(no_of_sprite_points == 3) {
    if(vw_pwr<=vh_pwr)
      {
          VH /= VW;
          VWH /= VW;
          VW=1;
          vh_pwr -= vw_pwr;
          vwh_pwr -= vw_pwr;
          vw_pwr=0;
      }
    else
      {
          VW /= VH;
          VWH /= VH;
          VH=1;
          vw_pwr -= vh_pwr;
          vwh_pwr -= vh_pwr;
          vh_pwr=0;
      }
}

if(no_of_sprite_points == 2) {
    a = x1p - x0p;
    b = -(y1p - y0p);
    c = x0p * VW;
    d = -b;
    e = a;
    f = y0p * VW;
    cxy = c + r*VW/2;
    cyy = f + r*VW/2;
    dnm_pwr = r_pwr+vw_pwr;
} else {
    a = (x1p - x0p) * VH;
    b = (x2p - x0p) * VW;
    c = x0p * VWH;
    d = (y1p - y0p) * VH;
    e = (y2p - y0p) * VW;
    f = y0p * VWH;
    cxy = c + r*VWH/2;
    cyy = f + r*VWH/2;
    dnm_pwr = r_pwr+vwh_pwr;
}

FourSlashesShift(cxy, dnm_pwr, &cxy_i, &cxy_f);
FourSlashesShift(cyy, dnm_pwr, &cyy_i, &cyy_f);
FourSlashesShift(a, dnm_pwr, &a_i, &a_f);
FourSlashesShift(b, dnm_pwr, &b_i, &b_f);
FourSlashesShift(d, dnm_pwr, &d_i, &d_f);
FourSlashesShift(e, dnm_pwr, &e_i, &e_f);
fracmask = (1 << dnm_pwr) - 1;

/* luma & alpha */
for (j = 0; j < warp_height;
     cxy_i+=b_i, cxy_f+=b_f, cyy_i+=e_i, cyy_f+=e_f, j++) {
    cxy_i += cxy_f >> dnm_pwr;
    cyy_i += cyy_f >> dnm_pwr;
    cxy_f &= fracmask;
    cyy_f &= fracmask;
    for (i = 0, cxx_i = cxy_i, cxx_f = cxy_f, cyx_i= cyy_i, cyx_f= cyy_f;
         i < warp_width;
         cxx_i+=a_i, cxx_f+=a_f, cyx_i+=d_i, cyx_f+=d_f, i++) {
     pel_warp = j * warp_width + i;
     cxx_i += cxx_f >> dnm_pwr;
     cyx_i += cyx_f >> dnm_pwr;
     cxx_f &= fracmask;
     cyx_f &= fracmask;

     if (cxx_i<0 || cyx_i<0 || cxx_i>((width-1)<<warpingaccuracy)||
         cyx_i>((height-1)<<warpingaccuracy))
       {
           dataYout[pel_warp] = 0;
           if (GetVopShape(vop)==0) /* rectangular */
             dataAout[pel_warp] = 255;
           else
             if (GetVopShape(vop)==1||GetVopShape(vop)==2)
               dataAout[pel_warp] = 0;
       }
     else
       {
           offset=(cyx_i>>warpingaccuracy)*width + (cxx_i>>warpingaccuracy);

           rx = cxx_i & warpmask;
           ry = cyx_i & warpmask;

           if (GetVopShape(vop)==0) /* rectangular */
             dataAout[pel_warp] = 255;
           else {
               dataAout[pel_warp] = InterpolatePixelValue(dataAin, offset,
                                             width, rx, ry, warpprecision,
                                             bias, sqr_wac);
           }
           if(dataAout[pel_warp]>=128) {
               dataAout[pel_warp]=255;

               dataYout[pel_warp] = InterpolatePixelValue(dataYin, offset,
                                         width, rx, ry, warpprecision,
                                         bias, sqr_wac);
           } else dataAout[pel_warp]=0;

       }
 }
}

SubsampleAlphaMap(GetVopA(vop),GetVopAuv(vop),GetVopShape(vop));

if(no_of_sprite_points==2) {
    c = 2 * VW * x0p - 16*VW;
    f = 2 * VW * y0p - 16*VW;
    cxy = a + b + c + 2*r*VW;
    cyy = d + e + f + 2*r*VW;
    dnm_pwr = r_pwr+vw_pwr+2;
} else {
    c = 2 * VWH * x0p - 16*VWH;
    f = 2 * VWH * y0p - 16*VWH;
    cxy = a + b + c + 2*r*VWH;
    cyy = d + e + f + 2*r*VWH;
    dnm_pwr = r_pwr+vwh_pwr+2;
}

a_f *= 4;
b_f *= 4;
d_f *= 4;
e_f *= 4;
FourSlashesShift(cxy, dnm_pwr, &cxy_i, &cxy_f);
FourSlashesShift(cyy, dnm_pwr, &cyy_i, &cyy_f);
fracmask = (1 << dnm_pwr) - 1;

    /* chroma */
for (j = 0; j < warp_heightc;
     cxy_i+=b_i, cxy_f+=b_f, cyy_i+=e_i, cyy_f+=e_f, j++) {
    cxy_i += cxy_f >> dnm_pwr;
    cyy_i += cyy_f >> dnm_pwr;
    cxy_f &= fracmask;
    cyy_f &= fracmask;
    for (i = 0, cxx_i = cxy_i, cxx_f = cxy_f, cyx_i= cyy_i, cyx_f= cyy_f;
         i < warp_widthc;
         cxx_i+=a_i, cxx_f+=a_f, cyx_i+=d_i, cyx_f+=d_f, i++) {
     pel_warp = j * warp_widthc + i;
     cxx_i += (cxx_f >> dnm_pwr);
     cyx_i += (cyx_f >> dnm_pwr);
     cxx_f &= fracmask;
     cyx_f &= fracmask;

     if (cxx_i<0 || cyx_i <0 || cxx_i>((widthc-1)<<warpingaccuracy)||
         cyx_i>=((heightc-1)<<warpingaccuracy)) {
         dataUout[pel_warp] = 0;
         dataVout[pel_warp] = 0;
     } else {
         if(dataAuvout[pel_warp]>0) {
             offset = (cyx_i>>warpingaccuracy)*widthc+(cxx_i>>warpingaccuracy);

             rx = cxx_i & warpmask;
             ry = cyx_i & warpmask;

             dataUout[pel_warp] = InterpolatePixelValue(dataUin, offset,
                                             widthc, rx, ry, warpprecision,
                                             bias, sqr_wac);
             dataVout[pel_warp] = InterpolatePixelValue(dataVin, offset,
                                             widthc, rx, ry, warpprecision,
                                             bias, sqr_wac);
         }
     }
 }
}

FreeVop(tmp_sprite);
}

/***********************************************************CommentBegin******
 *
 * --    PerspectiveWarp()
 *
 * Author: Yoshinori Suzuki (Hitachi, Ltd.),
 *         Cecile Dufour (LEP/Philips France) and
 *         Frederic Dufaux (Digital Equipment Corp.)
 *
 * Created : 15-11-97	
 *
 * Purpose :  sprite warping using perspective transform
 * 
 * Arguments in : 
 *
 * Arguments in / out :	
 *
 * Return values :	
 *  None
 * Side effects :	
 *
 *
 * Description :	
 *
 * See also :
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/

Void PerspectiveWarp(Vop *vop)
{
Vop *sprite, *tmp_sprite;
Int no_of_sprite_points, warpingaccuracy;
Int width, height;
Int widthc, heightc;
Int warp_width, warp_height;
Int warp_widthc, warp_heightc;
Int left, top, hor_ref, ver_ref;
Int x0, y0, x1, y1, x2, y2, x3, y3;
Int x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p;
Double a, b, c, d, e, f, g, h, D;
Double denom, denomby2, num;
Int W, H, WH;
Int I, J, Ic, Jc;
Int i,j;
Int pel_warp;
Int bias, sqr_wac;
Int rx, ry;
Int cx, cy, offset;
TrajPoint *tmp_refpoint;
TrajPoint *tmp_trajpoint;

Int warpprecision, warpmask;

SInt *dataYin, *dataUin, *dataVin, *dataAin;
SInt *dataYout, *dataUout, *dataVout, *dataAout, *dataAuvout;

sprite = GetVopSprite(vop);
tmp_sprite = CloneVop(sprite);
VopPadding(tmp_sprite);
PutVopShape(GetVopShape(sprite),vop);

no_of_sprite_points = GetVopNoOfSpritePoints(vop);
warpingaccuracy = GetVopWarpingAccuracy(vop) + 1;
warpprecision = 1 << warpingaccuracy;
warpmask = warpprecision - 1;
sqr_wac = warpingaccuracy << 1;
bias = 1 << (sqr_wac - 1);

SetConstantImage(vop->y_chan, 0);
SetConstantImage(vop->a_chan, 0);
SetConstantImage(vop->a_uv_chan, 0);
SetConstantImage(vop->u_chan, 0);
SetConstantImage(vop->v_chan, 0);

dataYin = (SInt *) GetImageData(GetVopY(tmp_sprite));
dataUin = (SInt *) GetImageData(GetVopU(tmp_sprite));
dataVin = (SInt *) GetImageData(GetVopV(tmp_sprite));
dataAin = (SInt *) GetImageData(GetVopA(tmp_sprite));

dataYout = (SInt *) GetImageData(GetVopY(vop));
dataUout = (SInt *) GetImageData(GetVopU(vop));
dataVout = (SInt *) GetImageData(GetVopV(vop));
dataAout = (SInt *) GetImageData(GetVopA(vop));
dataAuvout = (SInt *) GetImageData(GetVopAuv(vop));

width = GetVopWidth(tmp_sprite);
height = GetVopHeight(tmp_sprite);
left = 2*(GetVopSpriteLeftEdge(vop) - 16);
top  = 2*(GetVopSpriteTopEdge(vop)  - 16);

hor_ref = GetVopHorSpatRef(vop);
ver_ref = GetVopVerSpatRef(vop);
warp_width = GetVopWidth(vop);
warp_height = GetVopHeight(vop);

widthc = width>>1;
heightc = height>>1;
warp_widthc = warp_width>>1;
warp_heightc = warp_height>>1;

tmp_refpoint = GetVopRefPointCoord(vop);
tmp_trajpoint = GetVopTrajPointCoord(vop);

x0 = tmp_refpoint[0].x;
y0 = tmp_refpoint[0].y;
x1 = tmp_refpoint[1].x;
y1 = tmp_refpoint[1].y;
x2 = tmp_refpoint[2].x;
y2 = tmp_refpoint[2].y;
x3 = tmp_refpoint[3].x;
y3 = tmp_refpoint[3].y;

x0p = tmp_trajpoint[0].x + 2*x0 - left;
y0p = tmp_trajpoint[0].y + 2*y0 - top;
x1p = tmp_trajpoint[1].x + 2*x1 - left;
y1p = tmp_trajpoint[1].y + 2*y1 - top;
x2p = tmp_trajpoint[2].x + 2*x2 - left;
y2p = tmp_trajpoint[2].y + 2*y2 - top;
x3p = tmp_trajpoint[3].x + 2*x3 - left;
y3p = tmp_trajpoint[3].y + 2*y3 - top;

x0 -= hor_ref;
y0 -= ver_ref;
x1 -= hor_ref;
y1 -= ver_ref;
x2 -= hor_ref;
y2 -= ver_ref;
x3 -= hor_ref;
y3 -= ver_ref;

x0p = x0p << (warpingaccuracy-1);
y0p = y0p << (warpingaccuracy-1);
x1p = x1p << (warpingaccuracy-1);
y1p = y1p << (warpingaccuracy-1);
x2p = x2p << (warpingaccuracy-1);
y2p = y2p << (warpingaccuracy-1);
x3p = x3p << (warpingaccuracy-1);
y3p = y3p << (warpingaccuracy-1);

W = x1 - x0;
H = y2 - y0;
WH = W*H;

D = (Double)(x1p - x3p)*(y2p - y3p) - (Double)(x2p - x3p)*(y1p - y3p);

g = ((Double)(x0p - x1p - x2p + x3p) * (y2p - y3p)
  - (Double)(y0p - y1p - y2p + y3p) * (x2p - x3p)) * H;

h = ((Double)(y0p - y1p - y2p + y3p) * (x1p - x3p)
  - (Double)(x0p - x1p - x2p + x3p) * (y1p - y3p)) * W;

a = D * (x1p - x0p) * H + g * x1p;
b = D * (x2p - x0p) * W + h * x2p;
c = D * x0p * WH;

d = D * (y1p - y0p) * H + g * y1p;
e = D * (y2p - y0p) * W + h * y2p;
f = D * y0p * WH;

    /* luma & alpha */
for (j = 0; j < warp_height; j++) {
  for (i = 0; i < warp_width; i++) {
      pel_warp = j * warp_width + i;
      I = (i - x0);
      J = (j - y0);
      denom = g * I + h * J + D*WH;
      denomby2 = denom/2;

      cx = MyFloatDiv((c + a * I + b * J), denom, denomby2);
      cy = MyFloatDiv((f + d * I + e * J), denom, denomby2);

      if (cx<0||cy<0||cx>((width-1)<<warpingaccuracy)||
          cy>((height-1)<<warpingaccuracy))
      {
           dataYout[pel_warp] = 0;
           if (GetVopShape(vop)==0) /* rectangular */
             dataAout[pel_warp] = 255;
           else
             if (GetVopShape(vop)==1||GetVopShape(vop)==2)
               dataAout[pel_warp] = 0;
      }
      else
      {

           offset=(cy>>warpingaccuracy)*width + (cx>>warpingaccuracy);

           rx = cx & warpmask;
           ry = cy & warpmask;

           if (GetVopShape(vop)==0) /* rectangular */
             dataAout[pel_warp] = 255;
           else {
              dataAout[pel_warp] = InterpolatePixelValue(dataAin, offset,
                                             width, rx, ry, warpprecision,
                                             bias, sqr_wac);
           }
           if(dataAout[pel_warp]>=128) {
               dataAout[pel_warp]=255;

              dataYout[pel_warp] = InterpolatePixelValue(dataYin, offset,
                                         width, rx, ry, warpprecision,
                                         bias, sqr_wac);
           }
           else dataAout[pel_warp]=0;
      }

  }
}

SubsampleAlphaMap(GetVopA(vop),GetVopAuv(vop),GetVopShape(vop));

    /* chroma */
for (j = 0; j < warp_heightc; j++) {
  for (i = 0; i < warp_widthc; i++) {
      pel_warp = j * warp_widthc + i;
      Ic = (4 * i - 2 * x0 + 1);
      Jc = (4 * j - 2 * y0 + 1);
      denom = 4 * g * Ic + 4 * h * Jc + 8*D*WH;
      denomby2 = denom/2;

      num = 4*c + 2 * a * Ic  + 2 * b * Jc -
           ((g * Ic + h * Jc + 2*D*WH)*(1<<warpingaccuracy));
      cx = MyFloatDiv(num, denom, denomby2);
      num = 4*f + 2 * d * Ic  + 2 * e * Jc -
           ((g * Ic + h * Jc + 2*D*WH)*(1<<warpingaccuracy));
      cy = MyFloatDiv(num, denom, denomby2);

      if (cx<0||cy<0||cx>((widthc-1)<<warpingaccuracy)||
          cy>((heightc-1)<<warpingaccuracy))
      {
          dataUout[pel_warp] = 0;
          dataVout[pel_warp] = 0;
      }
      else
      {

      if(dataAuvout[pel_warp]>0) {

         offset=(cy>>warpingaccuracy)*widthc + (cx>>warpingaccuracy);

         rx = cx & warpmask;
         ry = cy & warpmask;

         dataUout[pel_warp] = InterpolatePixelValue(dataUin, offset,
                                             widthc, rx, ry, warpprecision,
                                             bias, sqr_wac);
         dataVout[pel_warp] = InterpolatePixelValue(dataVin, offset,
                                             widthc, rx, ry, warpprecision,
                                             bias, sqr_wac);


      }
      }

  }
}

FreeVop(tmp_sprite);
}

/***********************************************************CommentBegin******
 *
 * --    LinearExtrapolation()
 *
 * Author: Yuichiro Nakaya, Hitachi, Ltd.
 *
 * Created : 14-11-97	
 *
 * Purpose : linear extrapolation for obtaining virtual corner vectors
 *           only requires the usage of 32-bit integer variables
 * 
 * Arguments in : 
 *
 * Arguments in / out :	
 *
 * Return values :	
 *  None
 * Side effects :	
 *
 *
 * Description :	
 *
 * See also :
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/

Int LinearExtrapolation(Int x0, Int x1, Int x0p, Int x1p, Int W, Int VW)
{
Int quot, res, ressum, extrapolated;

FourSlashes(x0p - (x0 << 4), W, &quot, &res);
extrapolated = quot * (W - VW);

FourSlashes(res * (W - VW), W, &quot, &res);
extrapolated += quot;
ressum = res;

FourSlashes(x1p - (x1 << 4), W, &quot, &res);
extrapolated += quot * VW + res;

FourSlashes(res * (VW - W), W, &quot, &res);
extrapolated += quot;
ressum += res;

FourSlashes(ressum, W, &quot, &res);
extrapolated += quot;

if(extrapolated >= 0) {
    if(res >= (W+1) / 2)
      extrapolated++;
} else
  if(res > W / 2)
    extrapolated++;

return(extrapolated);
}

/***********************************************************CommentBegin******
 *
 * --    FourSlashes()
 * --    FourSlashesShift()
 *
 * Author: Yuichiro Nakaya, Hitachi, Ltd.
 *
 * Created : 14-11-97	
 *
 * Purpose : emulate the "////" operator (integer division with 
 *           truncation towards the negative infinity) defined in the CD
 * 
 * Arguments in : 
 *
 * Arguments in / out :	
 *
 * Return values :	
 *  None
 * Side effects :	
 *
 *
 * Description :	
 *
 * See also :
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/

Void FourSlashes(Int num, Int denom, Int *quot, Int *res)
{
*quot =  num / denom;
if(*quot * denom == num)
  *res = 0;
else {
    if(num < 0) /* it is assumed that denom is larger than zero */
        *quot -= 1;
    *res = num - denom * *quot;
}
}

Void FourSlashesShift(Int num, Int denom_pwr, Int *quot, Int *res)
{
*quot =  abs(num) >> denom_pwr;
if(num < 0)
  *quot = -*quot;
if(*quot << denom_pwr == num)
  *res = 0;
else {
    if(num < 0)
        *quot -= 1;
    *res = num - (*quot << denom_pwr);
}
}

/***********************************************************CommentBegin******
 *
 * -- AddTraj -- reconstruct trajectories from differences
 *
 * Author :		
 *	Frederic Dufaux (Digital Equipment Corporation/ dufaux@crl.dec.com)
 *
 * Created :		
 *	02/03/97
 *
 * Purpose :		
 *
 * Arguments in : 
 * 
 * Arguments in / out : 
 *
 * Return values :	
 *
 * Side effects :	
 *	
 * Description : 
 *
 * See also :
 *
 * Modified : 
 *
 ***********************************************************CommentEnd********/

TrajPoint *
AddTraj (Int no_of_sprite_points, TrajPoint *difftraj)
{
  Int i;
  TrajPoint *traj;
  
traj = (TrajPoint *) emalloc(no_of_sprite_points*sizeof(TrajPoint));
 
  traj[0].x = difftraj[0].x;
  traj[0].y = difftraj[0].y;

  for (i=1; i<MIN(no_of_sprite_points,3); i++) 
  {
    traj[i].x = difftraj[i].x + traj[0].x;
    traj[i].y = difftraj[i].y + traj[0].y;
  }
  if (no_of_sprite_points==4)
  {
    traj[3].x = difftraj[3].x + traj[2].x + traj[1].x - traj[0].x;
    traj[3].y = difftraj[3].y + traj[2].y + traj[1].y - traj[0].y;
  }
  
 return(traj);

}

/***********************************************************CommentBegin******
 *
 * -- float_to_int()
 *
 * Author :		
 *	?, LEP
 *
 * Created :		
 *	16-10-96
 *
 * Purpose :  nearest integer: nearest to 0.5 is 0 
 *	 
 * Arguments in : 
 * 
 * Arguments in / out : 
 *
 * Return values :	
 *  
 * Side effects :	
 *	
 *
 * Description : 
 *
 * See also :
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/


Int  
float_to_int	( Float float_nb )

{
 Int	res;
 Float	dec;

 res = (Int) float_nb;
 dec = float_nb - res;

 if      ( dec > 0.5 )
	res +=1;
 else if ( dec < -0.5 )	
	res -=1; 

 return ( res );
}
/***********************************************************CommentBegin******
 *
 * -- float_to_int2()
 *
 * Author :		
 *	?, LEP
 *
 * Created :		
 *	16-10-96
 *
 * Purpose :  nearest integer: nearest to 0.5 is 1
 *	
 * 
 * Arguments in : 
 * 
 * Arguments in / out : 
 *
 * Return values :	
 *  None
 * Side effects :	
 *	
 *
 * Description : 
 *
 * See also :
 *	float_to_int (previous function) which rounds 0.5 to 0
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/


Int  
float_to_int2	( Float float_nb )

{
 Int	res;
 Float	dec;

 res = (Int) float_nb;
 dec = float_nb - res;

 if      ( dec >= 0.5 )
	res +=1;
 else if ( dec <= -0.5 )	
	res -=1; 

 return ( res );
}
/***********************************************************CommentBegin******
 *
 * -- PutSpritePieceInSprite -- Encrusts a piece of sprite into a static sprite
 *
 * Author :		
 *	Cecile Dufour LEP/Philips France > dufour@lep.research.philips.com
 *
 * Created :		
 *	16-09-97
 *
 * Purpose :		
 *	This function copies sprite pieces into a sprite
 * 
 * Arguments in : 
 *		sprite_piece: decoded sprite piece (it is a VOP)
 *		sprite: sprite to reconstruct 	
 *
 * Arguments in/out :	
 *	-
 *
 * Arguments out :	
 *	-
 *
 * Return values :	
 *	-
 *
 * Side effects :	
 *	-
 *
 * Description :	
 *
 * See also :
 *	PutSubImage (mom_image.c)
 *
 * Modified :		
 *
 ***********************************************************CommentEnd********/
Void PutSpritePieceInSprite( Vop *sprite_piece, Vop *sprite, 
							Int x_off, Int y_off)
{
Int	x_soff, y_soff, x_poff, y_poff, x_max, y_max;
SInt	*p_py,*p_pu,*p_pv,*p_pa, *p_pa_uv;
SInt	*p_sy,*p_su,*p_sv,*p_sa, *p_sa_uv;
Int	xdim_piece, ydim_piece, xdim_sprite, ydim_sprite;
Int	x,y;

p_py = (SInt *)GetImageData(GetVopY(sprite_piece));
p_pu = (SInt *)GetImageData(GetVopU(sprite_piece));
p_pv = (SInt *)GetImageData(GetVopV(sprite_piece));
p_pa = (SInt *)GetImageData(GetVopA(sprite_piece));
p_pa_uv = (SInt *)GetImageData(GetVopAuv(sprite_piece));

p_sy = (SInt *)GetImageData(GetVopY(sprite));
p_su = (SInt *)GetImageData(GetVopU(sprite));
p_sv = (SInt *)GetImageData(GetVopV(sprite));
p_sa = (SInt *)GetImageData(GetVopA(sprite));
p_sa_uv = (SInt *)GetImageData(GetVopAuv(sprite));


/*****Get images dimensions*****/
xdim_piece  = GetImageSizeX(sprite_piece->y_chan);
ydim_piece  = GetImageSizeY(sprite_piece->y_chan);
xdim_sprite = GetImageSizeX(sprite->y_chan);
ydim_sprite = GetImageSizeY(sprite->y_chan);

x_max = MAX(0,MIN(xdim_sprite-x_off,xdim_piece));
y_max = MAX(0,MIN(ydim_sprite-y_off,ydim_piece));
x_poff = xdim_piece - x_max;
y_poff = ydim_piece - y_max;
x_soff = xdim_sprite - x_max;
y_soff = ydim_sprite - y_max;


/* LUMINANCE */
p_sy  += y_off*xdim_sprite + x_off;
for(y=0; y<y_max; y++,  p_sy+=x_soff, p_py+=x_poff)
for(x=0; x<x_max; x++,  p_sy++,      p_py++)
	*p_sy = *p_py;
	
/* CHROMINANCE */
p_su  +=(y_off/2)*(xdim_sprite/2) + x_off/2;
for(y=0; y<y_max/2; y++, p_su+=x_soff/2, p_pu+=x_poff/2)
for(x=0; x<x_max/2; x++, p_su++,        p_pu++	)
	*p_su = *p_pu;
p_sv  += (y_off/2)*(xdim_sprite/2) + x_off/2;
for(y=0; y<y_max/2; y++, p_sv+=x_soff/2, p_pv+=x_poff/2)
for(x=0; x<x_max/2; x++, p_sv++,        p_pv++)
	*p_sv = *p_pv;
	
/* ALPHA PLANE */
p_sa  += y_off*xdim_sprite + x_off;
for(y=0; y<y_max; y++,  p_sa+=x_soff, p_pa+=x_poff)
for(x=0; x<x_max; x++,  p_sa++,      p_pa++)
	*p_sa = *p_pa;
p_sa_uv  += (y_off/2)*(xdim_sprite/2) + x_off/2;
for(y=0; y<y_max/2; y++, p_sa_uv+=x_soff/2, p_pa_uv+=x_poff/2)
for(x=0; x<x_max/2; x++, p_sa_uv++,        p_pa_uv++	)
	*p_sa_uv = *p_pa_uv;     

  
}
/***********************************************************CommentBegin******
 *
 * -- PutSpritePieceInSprite2 -- Encrusts a piece of sprite into a static sprite
 *
 * Author :		
 *	Cecile Dufour LEP/Philips France > dufour@lep.research.philips.com
 *
 * Created :		
 *	16-09-97
 *
 * Purpose :		
 *	This function copies sprite pieces into a sprite
 * 
 * Arguments in : 
 *		sprite_piece: decoded sprite piece (it is a VOP)
 *		sprite: sprite to reconstruct 	
 *
 * Arguments in/out :	
 *	-
 *
 * Arguments out :	
 *	-
 *
 * Return values :	
 *	-
 *
 * Side effects :	
 *	-
 *
 * Description :	
 *
 * See also :
 *	PutSubImage (mom_image.c)
 *
 * Modified :		
 *
 ***********************************************************CommentEnd********/
Void PutSpritePieceInSprite2( Vop *sprite_piece, Vop *sprite, 
						Int x_off, Int y_off, 
						Int *array, Int type_of_vop)
{
Int	x_soff, y_soff, x_poff, y_poff, x_max, y_max;
SInt	*p_py,*p_pu,*p_pv,*p_pa, *p_pa_uv;
SInt	*p_sy,*p_su,*p_sv,*p_sa, *p_sa_uv;
Int	xdim_piece, ydim_piece, xdim_sprite, ydim_sprite;
Int	x,y;
Int	numblocks_x, numblocks_y;
Int	i,j, mb_x, mb_y, val, VAL=0;

if (type_of_vop==0/*I_VOP*/)	VAL = BLOCK_PIECE_TO_TRANSMIT;
if (type_of_vop==1/*P_VOP*/)	VAL = BLOCK_UPDATE_TO_TRANSMIT;

p_py = (SInt *)GetImageData(GetVopY(sprite_piece));
p_pu = (SInt *)GetImageData(GetVopU(sprite_piece));
p_pv = (SInt *)GetImageData(GetVopV(sprite_piece));
p_pa = (SInt *)GetImageData(GetVopA(sprite_piece));
p_pa_uv = (SInt *)GetImageData(GetVopAuv(sprite_piece));

p_sy = (SInt *)GetImageData(GetVopY(sprite));
p_su = (SInt *)GetImageData(GetVopU(sprite));
p_sv = (SInt *)GetImageData(GetVopV(sprite));
p_sa = (SInt *)GetImageData(GetVopA(sprite));
p_sa_uv = (SInt *)GetImageData(GetVopAuv(sprite));


/*****Get images dimensions*****/
xdim_piece  = GetImageSizeX(sprite_piece->y_chan);
ydim_piece  = GetImageSizeY(sprite_piece->y_chan);
xdim_sprite = GetImageSizeX(sprite->y_chan);
ydim_sprite = GetImageSizeY(sprite->y_chan);
numblocks_x = xdim_sprite/16;
numblocks_y = ydim_sprite/16;

x_max = MAX(0,MIN(xdim_sprite-x_off,xdim_piece));
y_max = MAX(0,MIN(ydim_sprite-y_off,ydim_piece));
x_poff = xdim_piece - x_max;
y_poff = ydim_piece - y_max;
x_soff = xdim_sprite - x_max;
y_soff = ydim_sprite - y_max;



/* LUMINANCE and ALPHA PLANE */
p_sy  += y_off*xdim_sprite + x_off;
p_sa  += y_off*xdim_sprite + x_off;
j = y_off;
for (y=0         ; y<y_max; y++, p_sy+=x_soff, 
				 p_sa+=x_soff, 
				 p_py+=x_poff, 
				 p_pa+=x_poff, j++)
for (x=0, i=x_off; x<x_max; x++, p_sy++,
				 p_sa++,
				 p_py++,
				 p_pa++,       i++)
	{
	mb_x = i/16;
	mb_y = j/16;
	val = array[mb_y*numblocks_x+mb_x];
	if (val==VAL)
		{
		*p_sy = *p_py;
		*p_sa = *p_pa;
		}
	}
	
/* CHROMINANCE and SUBSAMPLED ALPHA_PLANE */
p_su     += (y_off/2)*(xdim_sprite/2) + x_off/2;
p_sv     += (y_off/2)*(xdim_sprite/2) + x_off/2;
p_sa_uv  += (y_off/2)*(xdim_sprite/2) + x_off/2;
j = y_off;
for(y=0         ; y<y_max/2; y++, p_su    +=x_soff/2, 
				  p_sv    +=x_soff/2,
				  p_sa_uv +=x_soff/2,
				  p_pu    +=x_poff/2,
				  p_pv    +=x_poff/2, 
				  p_pa_uv +=x_poff/2, j+=2)
for(x=0, i=x_off; x<x_max/2; x++, p_su++,
				  p_sv++,
				  p_sa_uv++, 
				  p_pu++,
				  p_pv++,
				  p_pa_uv++,          i+=2)
	{
	mb_x = i/16;
	mb_y = j/16;
	val = array[mb_y*numblocks_x+mb_x];
	if (val==VAL)
		{
		*p_su    = *p_pu;
		*p_sv    = *p_pv;
		*p_sa_uv = *p_pa_uv;     
		}
	}
	
  
}

/***********************************************************CommentBegin******
 *
 * -- GetSpritePieceInSprite -- Cuts a piece of sprite into a static sprite
 *
 * Author :		
 *	Cecile Dufour LEP/Philips France > dufour@lep.research.philips.com
 *
 * Created :		
 *	03-10-97
 *
 * Purpose :		
 *	This function extracts sprite pieces from a sprite
 * 
 * Arguments in : 
 *		sprite_piece: VOP
 *		sprite: static sprite VOP 	
 *
 * Arguments in/out :	
 *	-
 *
 * Arguments out :	
 *	-
 *
 * Return values :	
 *	-
 *
 * Side effects :	
 *	-
 *
 * Description :	
 *
 * See also :
 *	GetSubImage (mom_image.c)
 *
 * Modified :		
 *
 ***********************************************************CommentEnd********/
Void GetSpritePieceInSprite( Vop *sprite_piece, Vop *sprite, 
						Int x_off, Int y_off)

{

GetSubImage(sprite->y_chan,    sprite_piece->y_chan,    x_off,   y_off);
GetSubImage(sprite->u_chan,    sprite_piece->u_chan,    x_off/2, y_off/2);
GetSubImage(sprite->v_chan,    sprite_piece->v_chan,    x_off/2, y_off/2);
GetSubImage(sprite->a_chan,    sprite_piece->a_chan,    x_off,   y_off);
GetSubImage(sprite->a_uv_chan, sprite_piece->a_uv_chan, x_off/2, y_off/2);
  
}
/***********************************************************CommentBegin******
 *
 * -- GetSpritePieceInSprite -- Cuts a piece of sprite into a static sprite
 *
 * Author :		
 *	Cecile Dufour LEP/Philips France > dufour@lep.research.philips.com
 *
 * Created :		
 *	03-10-97
 *
 * Purpose :		
 *	This function extracts sprite pieces from a sprite
 * 
 * Arguments in : 
 *		sprite_piece: VOP
 *		sprite: static sprite VOP 	
 *
 * Arguments in/out :	
 *	-
 *
 * Arguments out :	
 *	-
 *
 * Return values :	
 *	-
 *
 * Side effects :	
 *	-
 *
 * Description :	
 *
 * See also :
 *	GetSubImage (mom_image.c)
 *
 * Modified :		
 *
 ***********************************************************CommentEnd********/
Void GetSpritePieceInSprite2( Vop *sprite_piece, Vop *sprite, 
					Int x_off, Int y_off, 
					Int *array, Int type_of_vop)

{
Int	x_soff, y_soff, x_poff, y_poff, x_max, y_max;
SInt	*p_py,*p_pu,*p_pv,*p_pa, *p_pa_uv;
SInt	*p_sy,*p_su,*p_sv,*p_sa, *p_sa_uv;
Int	xdim_piece, ydim_piece, xdim_sprite, ydim_sprite;
Int	x,y;
Int	numblocks_x, numblocks_y;
Int	*p_array;
Int	i,j, mb_x, mb_y, val, VAL=0;

if (type_of_vop==0/*I_VOP*/)	VAL = BLOCK_PIECE_TO_TRANSMIT;
if (type_of_vop==1/*P_VOP*/)	VAL = BLOCK_UPDATE_TO_TRANSMIT;


p_py = (SInt *)GetImageData(GetVopY(sprite_piece));
p_pu = (SInt *)GetImageData(GetVopU(sprite_piece));
p_pv = (SInt *)GetImageData(GetVopV(sprite_piece));
p_pa = (SInt *)GetImageData(GetVopA(sprite_piece));
p_pa_uv = (SInt *)GetImageData(GetVopAuv(sprite_piece));

p_sy = (SInt *)GetImageData(GetVopY(sprite));
p_su = (SInt *)GetImageData(GetVopU(sprite));
p_sv = (SInt *)GetImageData(GetVopV(sprite));
p_sa = (SInt *)GetImageData(GetVopA(sprite));
p_sa_uv = (SInt *)GetImageData(GetVopAuv(sprite));


/*****Get images dimensions*****/
xdim_piece  = GetImageSizeX(sprite_piece->y_chan);
ydim_piece  = GetImageSizeY(sprite_piece->y_chan);
xdim_sprite = GetImageSizeX(sprite->y_chan);
ydim_sprite = GetImageSizeY(sprite->y_chan);
numblocks_x = xdim_sprite/16;
numblocks_y = ydim_sprite/16;
p_array = array;

x_max = MAX(0,MIN(xdim_sprite-x_off,xdim_piece));
y_max = MAX(0,MIN(ydim_sprite-y_off,ydim_piece));
x_poff = xdim_piece - x_max;
y_poff = ydim_piece - y_max;
x_soff = xdim_sprite - x_max;
y_soff = ydim_sprite - y_max;

/* ALPHA PLANE */
p_sa  += y_off*xdim_sprite + x_off;
j = y_off;
for(y=0         ; y<y_max; y++,  p_sa+=x_soff, p_pa+=x_poff, j++)
for(x=0, i=x_off; x<x_max; x++,  p_sa++,       p_pa++,       i++)
	{
	mb_x = i/16;
	mb_y = j/16;
	val = array[mb_y*numblocks_x+mb_x];
	if (val!=VAL)
		*p_pa = 0;
	else
		*p_pa = *p_sa;
	}
	
p_sa_uv  += (y_off/2)*(xdim_sprite/2) + x_off/2;
j = y_off;
for(y=0         ; y<y_max/2; y++, p_sa_uv+=x_soff/2, p_pa_uv+=x_poff/2, j+=2)
for(x=0, i=x_off; x<x_max/2; x++, p_sa_uv++,         p_pa_uv++,         i+=2)
	{
	mb_x = i/16;
	mb_y = j/16;
	val = array[mb_y*numblocks_x+mb_x];
	if (val!=VAL)
		*p_pa_uv = 0;
	else
		*p_pa_uv = *p_sa_uv;
	}

/* LUMINANCE */
p_sy  += y_off*xdim_sprite + x_off;
for(y=0; y<y_max; y++,  p_sy+=x_soff, p_py+=x_poff)
for(x=0, i=x_off; x<x_max; x++,  p_sy++,      p_py++)
	{
	*p_py = *p_sy;
	}
	
/* CHROMINANCE */
p_su  +=(y_off/2)*(xdim_sprite/2) + x_off/2;
p_sv  += (y_off/2)*(xdim_sprite/2) + x_off/2;
for(y=0; y<y_max/2; y++, p_su+=x_soff/2, p_pu+=x_poff/2, p_sv+=x_soff/2, p_pv+=x_poff/2)
for(x=0; x<x_max/2; x++, p_su++,         p_pu++	       , p_sv++,         p_pv++)
	{
	*p_pu = *p_su;
	*p_pv = *p_sv;
	}	
  
}  

/***********************************************************CommentBegin******
 *
 * --    MyFloatDiv
 *
 * Author :
 *      Frederic Dufaux, Digital Equipment Corp.
 *
 * Created :
 *      08-01-97
 *
 ***********************************************************CommentEnd********/
Int
MyFloatDiv(Double num, Double denom, Double denomby2)
{
Int ratio;

  /* rounds fractional values to nearest integer
     rounds half integer values towards positive infinity */

  if ((num>=0&&denom>=0) || (num<=0&&denom<=0))
    ratio = (Int) ((num + denomby2) / denom);
  else if (num>0 && denom<0 )
    ratio = (Int) ((num - (denom+1)/2) / denom);
  else
    ratio = (Int) ((num - (denom-1)/2) / denom);


  return(ratio);

}


