/******************************************************************************
 *                                                                          
 * This software module was originally developed by 
 *
 * Jan De Lameillieure (HHI / ACTS-MoMuSys).     	              	
 *
 * and edited by 
 *
 * Angel Pacheco (UPM / ACTS-MoMuSys).     		              	
 * Robert Danielsen (Telenor / ACTS-MoMuSys). 	    	              	
 * Michael Wollborn (TUH / ACTS-MoMuSys). 
 * Minhua Zhou (HHI / ACTS-MoMuSys).	    	              	
 * Cor Quist (KPN / ACTS-MoMuSys).     			              	
 *
 * 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:	alp_code_grey.c
 *
 * Author:	Jan De Lameillieure (HHI)
 * Created:	06-Nov-96
 *                                                                         
 * Description: Functions for the coding of grey scale shapes
 *
 * Notes: 	
 *
 * Modified:
 *
 *    16.06.97 Angel Pacheco: unified the TRANSPARENT modes.
 ***************************************************HeaderEnd*****************/

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

#include <stdio.h>
#include "momusys.h"
#include "mom_access.h"
#include "mom_image.h"
#include "vm_enc_defs.h"
#include "vm_common_defs.h"
#include "mot_est.h"		/* because of MBM_INTRA */
#include "mom_bitstream_i.h"
#include "text_util.h"
#include "text_bits.h"
#include "text_quant.h"
#include "putvlc.h"
#include "text_code_mb.h"
#include "alp_code_grey.h"
#include "zigzag.h"		/* added 14-NOV-1996 MW */

#define OPAQUE 255


/*************************************************CommentBegin****************
 *
 * -- ObtainSupport -- 
 *
 * Author :
 *	Jan De Lameillieure (HHI)
 *
 * Created :
 *	05-Sep-96
 *
 * Purpose :
 * 
 * Arguments in :
 *
 * Arguments in/out :
 *	none
 *
 * Arguments out :
 *	none
 *
 * Return values :
 *
 * Side effects :
 *	none
 *
 * Description :
 *
 * See also :
 *
 * Modified :
 *
 *************************************************CommentEnd******************/
void
ObtainSupport(Image *AlphaPlain)
{
  Int i;
  Short *alpha = (Short *) GetImageData(AlphaPlain);

  for (i=0;i<GetImageSizeY(AlphaPlain)*GetImageSizeX(AlphaPlain);i++)
    alpha[i] = (alpha[i]>0) ? BINARY_ALPHA : 0;
}

/*************************************************CommentBegin****************
 *
 * -- CodeGreyLevelAlpha -- 
 *
 * Author :
 *	Jan De Lameillieure (HHI)
 *
 * Created :
 *	05-Sep-96
 *
 * Purpose :
 * 
 * Arguments in :
 *
 * Arguments in/out :
 *	none
 *
 * Arguments out :
 *	none
 *
 * Return values :
 *
 * Side effects :
 *	none
 *
 * Description :
 *
 * See also :
 *
 * Modified :
 *
 *************************************************CommentEnd******************/
void
CodeGreyLevelAlpha(
	Vop *curr,
	Image *GreyLevelAlpha,
	Image *MotionCompensatedGreyLevelAlpha,
	Image *ReconstructedGreyLevelAlpha,
	Int QP,
	Image *MB_decisions,
	Image *shape_bitstream)
{
  Int mb_x,mb_y;

  for(mb_y=0;mb_y<(GetImageSizeY(GreyLevelAlpha)+MB_SIZE-1)/MB_SIZE;mb_y++)
    for(mb_x=0;mb_x<(GetImageSizeX(GreyLevelAlpha)+MB_SIZE-1)/MB_SIZE;mb_x++)
      CodeGreyLevelAlphaAB(curr,mb_x,mb_y,QP,MB_decisions,
	 GreyLevelAlpha,MotionCompensatedGreyLevelAlpha,ReconstructedGreyLevelAlpha,shape_bitstream);
}

/***
 * one2two()
 *
 * Small routine to convert a 1D block to a 2D block
 *
 * Written by Robert Danielsen, 16.10.96
 *
 ***/

Void one2two(Int one[], Int two[][8])
{
  Int i, j;
  
  for (j = 0; j < 8; j++)
    for (i =0; i < 8; i++)
      two[j][i] = one[j*8+i];
}

/*************************************************CommentBegin****************
 *
 * -- CodeGreyLevelAlphaAB -- 
 *
 * Author :
 *	Jan De Lameillieure (HHI)
 *
 * Created :
 *	05-Sep-96
 *
 * Purpose :
 * 
 * Arguments in :
 *
 * Arguments in/out :
 *	none
 *
 * Arguments out :
 *	none
 *
 * Return values :
 *
 * Side effects :
 *	none
 *
 * Description :
 *
 * Note :
 *	there is no size conversion (shape rate control) for gray-level alpha values
 *
 * See also :
 *
 * Modified :
 *	27.02.97 Robert Danielsen: Added type parameter to signal luma or
 *			chroma to the nonlinear quantization.
 *      21-APR-97 Jan De Lameillieure : added initialisation of CBPA
 *      21-APR-97 Jan De Lameillieure : replaced idctref() by BlockIDCT()
 *      21-APR-97 Jan De Lameillieure : added intra clipping
 *      21-APR-97 Jan De Lameillieure : replaced Quant() by BlockQuant()
 *                                      and Dequant() by BlockDequant()
 *	22-APR-97 Michael Wollborn: changed name of BlockQuant to 
 *			BlockQuantH263 (and for dequant. also) and changed
 *			stuff for MPEG-like quantization
 *
 *************************************************CommentEnd******************/
void
CodeGreyLevelAlphaAB(
	Vop *curr,	/* necessary to know VOP prediction type (influences CODA) and QP */
	Int mb_x,
	Int mb_y,
	Int QP,
	Image *MB_decisions,
	Image *GreyLevelAlpha,
	Image *MotionCompensatedGreyLevelAlpha,
	Image *ReconstructedGreyLevelAlpha,
	Image *shape_bitstream)
{
  Int i,j,k,l;
  Image *mblock, *mc_mblock;
  Short *pixel, *mc_pixel;
  UChar alpha_mb_all_opaque, alpha_residue_all_zero;
  Int Mode;
  Int coeff[64];
  Int *coeff_ind = coeff;
  Int qcoeff[256];
  Int *qcoeff_ind;
  Int rcoeff[256];
  Int *rcoeff_ind;
  Int f[64];
  Int f_ind[8][8];
  Int block_nr;
  Int MB_tranps_pattern[4]={0,0,0,0};
  Int CBPA=0;			/* JDL 21-APR-97 : initialised CBPA */
  Short *ReconstructedGreyLevelAlpha_pointer = (Short *)GetImageData(ReconstructedGreyLevelAlpha);
  Short *MB_decisions_pointer = (Short *) GetImageData(MB_decisions);
  Int type;
  UChar all_zero_coefficients;
  Int *qmat;

  mblock = AllocImage(16,16,SHORT_TYPE);
  GetSubImage(GreyLevelAlpha,mblock,mb_x*MB_SIZE,mb_y*MB_SIZE);
  pixel = (Short *)GetImageData(mblock);


  Mode = MB_decisions_pointer[mb_y*GetImageSizeX(MB_decisions) + mb_x];

  if ((GetVopPredictionType(curr) == I_VOP) 
  		|| (Mode == MBM_INTRA) 
		|| (Mode == MBM_SPRITE)) {
 
    alpha_mb_all_opaque = 1;
    for (i=0; i<MB_SIZE; i++) 
      for (j=0; j<MB_SIZE; j++) 
	alpha_mb_all_opaque *= (pixel[i*MB_SIZE+j] == 255);

    /* writing CODA */
    BitstreamPutBits(shape_bitstream, (alpha_mb_all_opaque) ? 1 : 0, 1);

    if (!alpha_mb_all_opaque) {

      block_nr=0;
      for (i=0; i<MB_SIZE; i+=8) 
	for (j=0; j<MB_SIZE; j+=8) {
	  for (k=0; k<8; k++) 
	    for (l=0; l<8; l++) 
	      f[k*8+l] = pixel[(i+k)*MB_SIZE + (j+l)];

	  one2two(f, f_ind);
	  BlockDCT (f_ind, coeff_ind);

	  all_zero_coefficients=1;
	  for (k=0; k<8; k++) 
	    for (l=0; l<8; l++) 
	      if (coeff_ind[k*8+l])
		all_zero_coefficients=0;

	  qcoeff_ind = &(qcoeff[block_nr*64]);

	  if (all_zero_coefficients) {
	    for (k=0; k<8; k++) 
	      for (l=0; l<8; l++) 
		qcoeff_ind[k*(MB_SIZE/2) + l] = 0;
	  }
	  else {
	    if (block_nr < 4) type = 1;
	    else type = 2;

	    /* MW 22-APR-1997 Changes for MPEG quantization */
	    if(GetVopQuantType(curr))
	      {
		if(Mode==MODE_INTRA || Mode==MODE_INTRA_Q)
		  qmat = GetVopGrayIntraQuantMat(curr);
		else
		  qmat = GetVopGrayNonintraQuantMat(curr);

		BlockQuantMPEG(coeff_ind,QP,Mode,type,qmat,qcoeff_ind,255);
	      }
	    else
	      BlockQuantH263(coeff_ind,QP,Mode,type,qcoeff_ind,255); 
          }


	  for (k=0; k<8; k++) 
	    for (l=0; l<8; l++) 
	      if (qcoeff_ind[k*8+l])
		CBPA |= 1<<(3-block_nr);

	  block_nr++;
	} 

    /*  cbpa = CBPA^15;	*/ /* in gray-level shape coding always use 3rd column 
			   of table 26 in VM3.1 (P-VOP), even for I-VOP */
      PutCBPY(CBPA,0,MB_tranps_pattern,shape_bitstream);

      CodeAlphaBlockData(qcoeff, Mode, CBPA, 64, 
		mb_x, GetVopIntraACDCPredDisable(curr), shape_bitstream);

      block_nr=0;
      for (i=0; i<MB_SIZE; i+=8) 
	for (j=0; j<MB_SIZE; j+=8) {
	  qcoeff_ind = &(qcoeff[block_nr*64]);
	  rcoeff_ind = &(rcoeff[block_nr*64]);

	  if (block_nr < 4) type = 1;
	  else type = 2;

	  /* MW 22-APR-1997 Changes for MPEG quantization */
	  if(GetVopQuantType(curr))
	    {
	      if(Mode==MODE_INTRA || Mode==MODE_INTRA_Q)
	        qmat = GetVopGrayIntraQuantMat(curr);
	      else
	        qmat = GetVopGrayNonintraQuantMat(curr);

	      BlockDequantMPEG(qcoeff_ind,QP,Mode,type,qmat,rcoeff_ind);
	    }
	  else
	    BlockDequantH263(qcoeff_ind,QP,Mode,type,rcoeff_ind); 
 

	  BlockIDCT (rcoeff_ind, f_ind,GetVopBrightWhite(curr)); 

	  for (k=0;k<8;k++)
	    for (l=0;l<8;l++)
	      f_ind[k][l] =  MIN(255,MAX(0,f_ind[k][l]));  /* intra clipping */


	  for (k=0; k<8; k++) 
	    for (l=0; l<8; l++) 
	      ReconstructedGreyLevelAlpha_pointer[(mb_y*MB_SIZE+i+k)*GetImageSizeX(ReconstructedGreyLevelAlpha) + (mb_x*MB_SIZE+j+l)]
	        = f_ind[k][l];
	  block_nr++;
	}
    }
    else {	/* the whole alpha macroblock is opaque */
      for (i=0; i<MB_SIZE; i++) 
	for (j=0; j<MB_SIZE; j++) 
	  ReconstructedGreyLevelAlpha_pointer[(mb_y*MB_SIZE+i)*GetImageSizeX(ReconstructedGreyLevelAlpha) + (mb_x*MB_SIZE+j)] = OPAQUE;
    }
  }
  else {	/* P-VOP and not an intra-MB */

    mc_mblock = AllocImage(16,16,SHORT_TYPE);
    GetSubImage(MotionCompensatedGreyLevelAlpha,mc_mblock,mb_x*MB_SIZE,mb_y*MB_SIZE);
    mc_pixel = (Short *)GetImageData(mc_mblock);

    alpha_residue_all_zero = 1;
    alpha_mb_all_opaque = 1;
    for (i=0; i<MB_SIZE; i++) 
      for (j=0; j<MB_SIZE; j++) {
	alpha_mb_all_opaque *= (pixel[i*MB_SIZE+j] == 255);
	alpha_residue_all_zero *= (pixel[i*MB_SIZE+j] - mc_pixel[i*MB_SIZE+j] == 0);
      }

    /* writing CODA */
    if (alpha_residue_all_zero)
      BitstreamPutBits(shape_bitstream, 1, 1);
    else
      if (alpha_mb_all_opaque)
	BitstreamPutBits(shape_bitstream, 1, 2);
      else 
	BitstreamPutBits(shape_bitstream, 0, 2);

    if (alpha_residue_all_zero) {
      for (i=0; i<MB_SIZE; i++) 
	for (j=0; j<MB_SIZE; j++) 
	  ReconstructedGreyLevelAlpha_pointer[(mb_y*MB_SIZE+i)*GetImageSizeX(ReconstructedGreyLevelAlpha) + (mb_x*MB_SIZE+j)] = mc_pixel[i*MB_SIZE+j];
    }
    else
      if (alpha_mb_all_opaque) {
	for (i=0; i<MB_SIZE; i++) 
	  for (j=0; j<MB_SIZE; j++) 
	    ReconstructedGreyLevelAlpha_pointer[(mb_y*MB_SIZE+i)*GetImageSizeX(ReconstructedGreyLevelAlpha) + (mb_x*MB_SIZE+j)] = OPAQUE;
      }
      else {

	block_nr=0;
	for (i=0; i<MB_SIZE; i+=8) 
	  for (j=0; j<MB_SIZE; j+=8) {
	    for (k=0; k<8; k++) 
	      for (l=0; l<8; l++) 
		f[k*8+l] = pixel[(i+k)*MB_SIZE + (j+l)] - mc_pixel[(i+k)*MB_SIZE + (j+l)];


	    one2two(f, f_ind);
	    BlockDCT (f_ind, coeff_ind);

	    qcoeff_ind = &(qcoeff[block_nr*64]);

	    if (block_nr < 4) type = 1;
	    else type = 2;

	    /* MW 22-APR-1997 Changes for MPEG quantization */
	    if(GetVopQuantType(curr))
	      {
		if(Mode==MODE_INTRA || Mode==MODE_INTRA_Q)
		  qmat = GetVopGrayIntraQuantMat(curr);
		else
		  qmat = GetVopGrayNonintraQuantMat(curr);

		BlockQuantMPEG(coeff_ind,QP,Mode,type,qmat,qcoeff_ind,255);
	      }
	    else
	      BlockQuantH263(coeff_ind,QP,Mode,type,qcoeff_ind,255); 


	    for (k=0; k<8; k++) 
	      for (l=0; l<8; l++) 
		if (qcoeff_ind[k*8+l])
		  CBPA |= 1<<(3-block_nr);

	    block_nr++;
	  } 

	/*cbpa = CBPA^15;*/	/* in gray-level shape coding always use 3rd column 
			     of table 26 in VM3.1 (P-VOP), even for I-VOP */
	PutCBPY(CBPA,0,MB_tranps_pattern,shape_bitstream);
   

	CodeAlphaBlockData(qcoeff, Mode, CBPA, 64, 
		  mb_x, GetVopIntraACDCPredDisable(curr), shape_bitstream);

	block_nr=0;
	for (i=0; i<MB_SIZE; i+=8) 
	  for (j=0; j<MB_SIZE; j+=8) {
	    qcoeff_ind = &(qcoeff[block_nr*64]);
	    rcoeff_ind = &(rcoeff[block_nr*64]);

	    if (block_nr < 4) type = 1;
	    else type = 2;

	    /* MW 22-APR-1997 Changes for MPEG quantization */
	    if(GetVopQuantType(curr))
	      {
		if(Mode==MODE_INTRA || Mode==MODE_INTRA_Q)
	          qmat = GetVopGrayIntraQuantMat(curr);
		else
	          qmat = GetVopGrayNonintraQuantMat(curr);

		BlockDequantMPEG(qcoeff_ind,QP,Mode,type,qmat,rcoeff_ind);
	      }
	    else
	      BlockDequantH263(qcoeff_ind,QP,Mode,type,rcoeff_ind); 


	    BlockIDCT (rcoeff_ind, f_ind,GetVopBrightWhite(curr)); 

	    for (k=0; k<8; k++) 
	      for (l=0; l<8; l++) 
		ReconstructedGreyLevelAlpha_pointer[(mb_y*MB_SIZE+i+k)*GetImageSizeX(ReconstructedGreyLevelAlpha) + (mb_x*MB_SIZE+j+l)]
		  = MIN(255,MAX(0,f_ind[k][l] + mc_pixel[(i+k)*MB_SIZE + (j+l)]));	/* clipping */

	    block_nr++;
	  }

      }

    FreeImage(mc_mblock);                   
  }

  FreeImage(mblock);                   
}

/***********************************************************CommentBegin******
 *
 * -- CodeAlphaBLockData -- codes alpha block data
 *
 * Author : Jan De Lameillieure (HHI)
 *	    Cor Quist (KPN)		(programmed the function Bits_CountCoeff(), 
 *					 on which this function is based)
 *	
 * Created : 09-Sep-96
 *	
 *
 * Purpose :		
 *	codes the DCT coded gray-level alpha values
 * 
 * Arguments in : 	
 *	Int *qcoeff : quantized dct-coefficients
 * 	Int Mode : encoding mode
 * 	Int CBP : coded block pattern
 * 	Int ncoeffs : number of coefficients per block
 * 	Int x_pos : the horizontal position of the macroblock in the vop
 *      Int intra_dcpred_disable : disable the intradc prediction
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	Bits *bits : struct to count the number of texture bits 
 * 	Image *bitstream : output bitstream
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *       The intradc prediction can be switched off by setting the variable int 
 *       radc_pred_disable to '1'.
 *
 * See also :
 *	
 *
 * Modified :
 *     03-09-96 Cor Quist (KPN) added intra_dcpred_disable, removed OLDINTRADC
 *	06.11.96 Robert Danielsen: Changed quite a bit for new zigzag and VLC
 *	28.01.97 Robert Danielsen: Changed zigzag-scanning again
 *
 ***********************************************************CommentEnd********/

Void CodeAlphaBlockData (Int *qcoeff, Int Mode, Int CBPA, Int ncoeffs, 
			 Int x_pos, Int intra_dcpred_disable, Image *bitstream)
{
  
    Int i, m, coeff[64];
    Int predictor;
    Int delta_INTRADC;

    static Int previous_mode = MODE_INTER;
    static Int previous_x_pos = 0;
  
    static Int previous_A_INTRADC = 128;
  	
    if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q)
    {
	for (i = 0; i < 4; i++)
	{
	    /* Do the zigzag scanning of coefficients */
	    for (m = 0; m < 64; m++) /* found by Angel */
		*(coeff + zigzag[m]) = qcoeff[i*ncoeffs+m];

	    /* encode INTRADC */
	  
	    if (intra_dcpred_disable) /* intradc prediction off */
	    {
		if (coeff[0] != 128)
		{
		    BitstreamPutBits(bitstream, (long)(coeff[0]), 8L);
		}
		else
		{
		    BitstreamPutBits(bitstream, 255L, 8L);
		}
	    }

	    else  /* intradc prediction on */
	    {
	      
		/* new DPCM coding of INTRADC */
	      
		if ( i == 0 )
		{		/* first block in macroblock */
		    if ( x_pos == 0 )
		    {	/* left edge */
			predictor = 128;
		    }
		    else
		    {
			if ( previous_x_pos == (x_pos -1 )  && 
			     (previous_mode == MODE_INTRA || previous_mode == MODE_INTRA_Q ))
			{
			  
			    predictor = previous_A_INTRADC;
			}
			else
			{
			    predictor = 128;
			}
		    }
		}
		else
		{
		    predictor = previous_A_INTRADC;
		}
	      
		delta_INTRADC = coeff[0] - predictor;
	      
		IntraDC_dpcm(delta_INTRADC, 1, bitstream);
	      
		previous_A_INTRADC = coeff[0];
	      
		/* end */
	    }    
	  
	    if ((i==0 && CBPA&8) || (i==1 && CBPA&4) ||
		(i==2 && CBPA&2) || (i==3 && CBPA&1) )
	    {
		CodeCoeff(1,Mode, coeff,i,ncoeffs, bitstream);
	    }
	}
    }
    else
    {	/* inter block encoding */
	for (i = 0; i < 4; i++)
	{
	    if ((i==0 && CBPA&8) || 
		(i==1 && CBPA&4) ||
		(i==2 && CBPA&2) || 
		(i==3 && CBPA&1) )
	    {
		CodeCoeff(0,Mode, coeff, i, ncoeffs, bitstream);
	    }
	}
    }
  
    previous_mode = Mode;
    previous_x_pos = x_pos;
}



/*************************************************CommentBegin****************
 *
 * -- CopyReconstructedGreyLevelAlphaToVop -- 
 *
 * Author :
 *	Jan De Lameillieure (HHI)
 *
 * Created :
 *	09-Sep-96
 *
 * Purpose :
 * 
 * Arguments in :
 *
 * Arguments in/out :
 *	Image *a_chan : as input the reconstructed support function (binary shape), 
 *                  as output the reconstructed grey level alpha values
 *
 * Arguments out :
 *	none
 *
 * Return values :
 *
 * Side effects :
 *	none
 *
 * Description :
 *
 * Note :
 *
 * See also :
 *
 * Modified :
 *
 *************************************************CommentEnd******************/
void
CopyReconstructedGreyLevelAlphaToVop(
  Image *ReconstructedGreyLevelAlpha, 
  Image *a_chan)
{
  Int i;
  Short *rec_grey_alpha_pntr = (Short *)GetImageData(ReconstructedGreyLevelAlpha);
  Short *a_chan_pntr = (Short *)GetImageData(a_chan);
  
  for (i=0;i<GetImageSizeX(ReconstructedGreyLevelAlpha)*GetImageSizeY(ReconstructedGreyLevelAlpha);i++)
    a_chan_pntr[i] = (a_chan_pntr[i] == BINARY_ALPHA) ? rec_grey_alpha_pntr[i] : 0;
}
