/*****************************************************************************
 *
 * This software module was originally developed by
 *
 *   Noel O'Connor (Teltec DCU / ACTS-MoMuSyS)
 *
 * and edited by
 * 
 *   Robert Danielsen (Telenor / ACTS-MoMuSyS)
 *   Michael Wollborn (TUH / 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) 1996
 *
 *****************************************************************************/

/***********************************************************HeaderBegin*******
 *                                                                         
 * File:	vm_compos.c
 *
 * Author:	Noel O'Connor
 * Created:	3-March-1996 
 *                                                                         
 * Description: 
 *
 * Notes: 	
 *
 * Modified:
 *	21.04.96 Robert Danielsen: Reformatted. New headers.
 *	13.05.96 Noel O'Connor: Allow for non-perfect series of
 *			 comp_order values
 *	23.07.96 Michael Wollborn: use binary compos. mode also
 *			 in full-frame mode
 *	20-MAR-97 : Jan De Lameillieure (HHI) : added different
 *			subsampling between binary and greyscale alpha planes
 * 
 ***********************************************************HeaderEnd*********/

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

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "vm_common_defs.h" /* added 20-MAR-97, JDL, because of "BINARY_ALPHA" */
#include "vm_compos.h"

/***********************************************************CommentBegin******
 *
 * -- Compositor -- 
 *
 * Author :		
 *	Noel O'Connor
 *
 * Created :		
 *	3-March-1996   
 *
 * Purpose :		
 *	Given a list of vops to be composited, this function recursively
 * 	blends the vops by composition order onto the image fields of
 * 	a display vop.
 * 
 * Arguments in : 	
 *	Int vop_levels - The number of vops in list
 *	Vop *list - Pointer to the list of vops to be composited
 *
 * Arguments in/out :	
 *	Vop *display_vop - Pointer to the vop whose image fields on
 *	return from this function contain the blended image fields.
 *
 * Arguments out :	
 *	-
 *
 * Return values :	
 *	none
 *
 * Side effects :	
 *	* The display vop is assumed to be allocated to the 
 *	  required dimensions BEFORE this function is called.
 *	* Proper vop scaling is NOT currently supported.
 *	* Proper subsampling of the alpha map for blending is 
 *	  currently NOT supported.
 *	* It is assumed that the vops in the list passed to this
 *	  function are BOUNDED vops (i.e. the image fields consist
 *	  of the vop bounding rectagle justified to be an integer
 *	  number of 16x16 blocks
 *
 * Description :	
 *	-
 *
 * See also :
 *	-
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/
 
Void
Compositor(Int vop_levels, Vop *list, Vop *display_vop)
{
    Vop		*overlay_vop,
	*curr_vop;

    Int		comp_order,
	num_processed,
	visible;

    Image *data;

    UInt  x,
	y;
                
    /* Initialise display vop */
    /* Alpha plane transparent */
    data = GetVopA(display_vop); 
    SetConstantImage(data,0);   

    /* Y = 0 */
    data = GetVopY(display_vop);
    SetConstantImage(data,0);   

    /* U = 127 */
    data = GetVopU(display_vop);
    SetConstantImage(data,127); 

    /* V = 127 */
    data = GetVopV(display_vop);
    SetConstantImage(data,127);

    /* Process vops by composition order untill all vops in the
       list are processed. Allow for a non-perfect series of
       comp_orders e.g. 0 1 4 6 etc. */
    num_processed = 0;
    comp_order = 0;

    while (num_processed < vop_levels)
    {
	/* Use vop with req'd composition order */
	curr_vop = GetVopByCompOrder(list, comp_order);
	
	/* check if such a vop exists */
	if(curr_vop != NULL)
	{
	    /* Only overlay a vop if it is visible */
	    visible = GetVopVisibility(curr_vop);
   
	    if(visible)
	    {
		/* Allocate memory for the overlay vop */
		data = GetVopA(curr_vop);
		x = GetImageSizeX(data);
		y = GetImageSizeY(data);
		overlay_vop = AllocVop(x,y); 
            
		/* Set up temporary overlay vop to work with */
		CopyVop(curr_vop, overlay_vop);
   
		/* Perform vop scaling on overlay vop */
		ScaleVop(overlay_vop);
 
		/* Blend overlay YUVa data with display YUVa data */
		BlendVops(overlay_vop, display_vop);
					
		num_processed++;	
	   

		/* Deallocate memory for overlay vop */
		FreeVop(overlay_vop);

	    } /* if visible */
   
    	} /* if exist */

	comp_order++;
    }

    return;
}
 
/***********************************************************CommentBegin******
 *
 * -- ScaleVop -- 
 *
 * Author :		
 *	Noel O'Connor
 *
 * Created :		
 *	3-March-1996    
 *
 * Purpose :		
 *	This function scales the image fields of a vop according to the
 * 	value in the "scaling" field of the vop structure. The
 * 	amount is scaling is specified by 2^vop->scaling.
 * 
 * Arguments in : 	
 *	Vop *vop - pointer to vop to be scaled
 *
 * Arguments in/out :	
 *	-
 *
 * Arguments out :	
 *	-
 *
 * Return values :	
 *	none
 *
 * Side effects :	
 *	In this early  implementation scaling is NOT supported!
 *	A scaling of 1 is assumed for the time being.
 *
 * Description :	
 *	-
 *
 * See also :
 *	
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/

Void
ScaleVop(Vop *vop)
{
  Int			   x,
    y,
    scale;

  Image         *a_chan_scale,
    *y_chan_scale,
    *u_chan_scale,
    *v_chan_scale,
    *a_chan,
    *y_chan,
    *u_chan,
    *v_chan;


  /* Calculate scaling */
  scale = GetVopScaling(vop);

	if (scale != 0)
	{
  scale = 1<<scale;

  a_chan = GetVopA(vop);
  y_chan = GetVopY(vop);
  u_chan = GetVopU(vop);
  v_chan = GetVopV(vop);

  /* Assume Alpha and Y have same dimensions */
  x = GetImageSizeX(a_chan);
  y = GetImageSizeY(a_chan);

  /* Scale Y and Alpha dimensions */
  x = x * scale;
  y = y * scale;

  /* Allocate momory accordingly */
  a_chan_scale = AllocImage(x,y,SHORT_TYPE);
  y_chan_scale = AllocImage(x,y,SHORT_TYPE);

  /* Assume U and V have same dimensions */
  x = GetImageSizeX(u_chan);
  y = GetImageSizeY(u_chan);

  /* Scale U and V dimensions */
  x = x * scale;
  y = y * scale;

  /* Allocate memory accordingly */	
  u_chan_scale = AllocImage(x,y,SHORT_TYPE);
  v_chan_scale = AllocImage(x,y,SHORT_TYPE);

  /****
   * Up-Sample Image Data
   * NOT SUPPORTED AS YET! For now just assume scale = 1 and copy data
   *
   * Also vop_width and vop_height will have to be updated in here
   *
   *****/
  CopyImage(a_chan,a_chan_scale);
  CopyImage(y_chan,y_chan_scale);
  CopyImage(u_chan,u_chan_scale);
  CopyImage(v_chan,v_chan_scale);

#if 0 /* No double freeing of images */

  /* Replace data in overlay vop by scaled data */
  FreeImage(a_chan);
  FreeImage(y_chan);
  FreeImage(u_chan);
  FreeImage(v_chan);

#endif

  PutVopA(a_chan_scale,vop);
  PutVopY(y_chan_scale,vop);
  PutVopU(u_chan_scale,vop);
  PutVopV(v_chan_scale,vop);
	}
  return;
}

/***********************************************************CommentBegin******
 *
 * -- BlendVops -- 
 *
 * Author :		
 *	Noel O'Connor
 *
 * Created :		
 *	3-March-1996    
 *
 * Purpose :		
 *	This function performs the actual blending of the image fields
 * 	of two vops (image level).
 * 
 * Arguments in : 	
 *	overlay_vop - pointer to vop to be overlaid
 *
 * Arguments in/out :	
 *	bg_vop - pointer to background vop (i.e. vop ONTO
 *		which overlay_vop is overlaid.
 *
 * Arguments out :	
 *	-
 *
 * Return values :	
 *	none
 *
 * Side effects :	
 *	-
 *
 * Description :	
 *	-
 *
 * See also :
 *	-
 *
 * Modified :		
 *	    27.04.1997 Removed SubSampleAlpha()
 *
 ***********************************************************CommentEnd********/

Void
BlendVops(Vop *overlay_vop, Vop *bg_vop)
{
  Image	*a_chan_ovr,
    *y_chan_ovr,
    *u_chan_ovr,
    *v_chan_ovr,
    *y_chan_bg,
    *u_chan_bg,
    *v_chan_bg,
    *sub_a_chan;

  Int		
    hor_spat_ref,
    ver_spat_ref,
    binary;


  /* Use YUVa data of overlay vop */
  a_chan_ovr = GetVopA(overlay_vop);
  y_chan_ovr = GetVopY(overlay_vop);
  u_chan_ovr = GetVopU(overlay_vop);
  v_chan_ovr = GetVopV(overlay_vop);

  /* Use YUV data of background vop */
  y_chan_bg = GetVopY(bg_vop);
  u_chan_bg = GetVopU(bg_vop);
  v_chan_bg = GetVopV(bg_vop);
	
  hor_spat_ref = GetVopHorSpatRef(overlay_vop);
  ver_spat_ref = GetVopVerSpatRef(overlay_vop);

  /* Binary or grey level blending? */
   if (GetVopShape(overlay_vop)==2)
   binary = 0;
  else binary =1;
  
 	
  /* Blend Y components - blending is done over the entire
     image field passed in. It is assumed that this field
     is the vop bounding box*/
  Blend(hor_spat_ref,ver_spat_ref,a_chan_ovr,y_chan_ovr,binary,y_chan_bg);
	
		
   sub_a_chan = GetVopAuv(overlay_vop);
	
  /* Down sample composition information */
  hor_spat_ref = hor_spat_ref/2;
  ver_spat_ref = ver_spat_ref/2;
	
  /* Blend U and V components */
  Blend(hor_spat_ref,ver_spat_ref,sub_a_chan,u_chan_ovr,binary,u_chan_bg);
  Blend(hor_spat_ref,ver_spat_ref,sub_a_chan,v_chan_ovr,binary,v_chan_bg); 
   
    

  return;
}

/***********************************************************CommentBegin******
 *
 * -- Blend -- 
 *
 * Author :		
 *	Noel O'Connor
 *
 * Created :		
 *	3-March-1996
 *
 * Purpose :		
 *	This function performs the actual blending of the image fields
 * 	of two vops (pixel level).
 * 
 * Arguments in : 	
 *	ref_x - horizontal spatial reference of overlay in display
 *	ref_y - vertical spatial reference of overlay in display
 *	a_image - pointer to the alpha map
 *	ovr_image - pointer to the image to be overlaid
 *	binary - Flag for binary or GL blending
 *
 * Arguments in/out :	
 *	bg_image - pointer to the background image
 *
 * Arguments out :	
 *	-
 *
 * Return values :	
 *	none
 *
 * Side effects :	
 *	The overlay image fields are assumed to be BOUNDED vops.
 *
 * Description :	
 *	-
 *
 * See also :
 *	-
 *
 * Modified :		
 *	     26.05.97 Minhua Zhou: to allow blending with negative upper_left corredinates
 *
 ***********************************************************CommentEnd********/

Void
Blend(Int ref_x,Int ref_y, Image *a_image, Image *ovr_image, Int binary, Image *bg_image)
{

  Int			    width,
    height,
    disp_size_x,
    disp_size_y,
    disp_start_x,
    disp_start_y,
    disp_end_x,
    disp_end_y,
    x_pos_start,
    x_pos_end,
    y_pos_start,
    y_pos_end,
    x,y,
    disp_pos,over_pos; 
               
  SInt			*alpha,
    *ovr_data,
    *bg_data;

 

  /* Assume extracted vop (ie image fields are vop bounded) */
  width = GetImageSizeX(a_image);
  height = GetImageSizeY(a_image);            

  /* Calculate starting and ending coordinates for vop in display vop */
  disp_start_x = ref_x;
  disp_start_y = ref_y;
  disp_end_x = ref_x + width;
  disp_end_y = ref_y + height;

  /* Need to use size of display vop images */
  disp_size_x = GetImageSizeX(bg_image);
  disp_size_y = GetImageSizeY(bg_image);

  /* Get pel information of images */
  alpha = (SInt *)GetImageData(a_image);
  ovr_data = (SInt *)GetImageData(ovr_image);
  bg_data = (SInt *)GetImageData(bg_image); 
 
  y_pos_start = (disp_start_y>0)? disp_start_y:0;
  y_pos_end   = (disp_end_y>disp_size_y)? disp_size_y:disp_end_y;
  x_pos_start = (disp_start_x>0)? disp_start_x:0;
  x_pos_end   = (disp_end_x>disp_size_x)? disp_size_x:disp_end_x;
  if (binary)
  for (y =y_pos_start; y < y_pos_end; y++)
     for (x = x_pos_start;x<x_pos_end; x++) {
       disp_pos = y*disp_size_x+x;
       over_pos = (y-disp_start_y)*width + x - disp_start_x;
       if (alpha[over_pos])
          bg_data[disp_pos] = ovr_data[over_pos]; 
  }  
  else
  for (y =y_pos_start; y < y_pos_end; y++)
     for (x = x_pos_start;x<x_pos_end; x++) {
       disp_pos = y*disp_size_x+x;
       over_pos = (y-disp_start_y)*width + x - disp_start_x;
       if (alpha[over_pos])
          bg_data[disp_pos] = ((255-alpha[over_pos])*bg_data[disp_pos]+alpha[over_pos]*ovr_data[over_pos])/255; 
  }  

  return;
}

/***********************************************************CommentBegin******
 *
 * -- SubsampleAlphaMap -- 
 *
 * Author :		
 *	Noel O'Connor
 *
 * Created :		
 *	3-March-1996  
 *
 * Purpose :		
 *	This function takes an input alpha map and subsamples by
 *	2 in both horizontal and vertical directions. This function
 *	is necessary for blending U & V components of a vop.
 * 
 * Arguments in : 	
 *	Image *a_in - pointer to input alpha map
 *
 * Arguments in/out :	
 *	Image *a_out - pointer to output alpha map
 *
 * Arguments out :	
 *	
 *
 * Return values :	
 *	none
 *
 * Side effects :	
 *	The subsampling currently supported is NOT CORRECT.
 *	The method used is a simple ("ad hoc") pixel
 *	averaging one.
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *	20-MAR-97 : Jan De Lameillieure (HHI) : added different subsampling
 *			between binary and greyscale alpha planes
 *
 ***********************************************************CommentEnd********/

Void
SubsampleAlphaMap(Image *a_in, Image *a_out, Int shape)
{

  Int 		i,j,
    x,
    y;
	

  SInt 		sum_val, 
    avg_val,
    *orig_data,
    *sub_data;

  UInt		width,
    height;

  width = GetImageSizeX(a_in);
  height = GetImageSizeY(a_in);

  orig_data = (SInt *)GetImageData(a_in);
  sub_data = (SInt *)GetImageData(a_out);
	
  if (shape == GREY_SCALE)
  {
      i=j=0;
      for (y=0;y<height;y+=2,j+=width)
	  for (x=0;x<width;x+=2,i++,j+=2) 
	  {	
	      sum_val=orig_data[j];
	      sum_val+=orig_data[j+1];
	      sum_val+=orig_data[j+width];
	      sum_val+=orig_data[j+width+1];
			
	      avg_val=(sum_val+2)/4;	/* JDL 20-MAR-97 : added rounding */
							
	      sub_data[i] = avg_val;
	  }
  }
  else
  {
      i=j=0;
      for (y=0;y<height;y+=2,j+=width)
	  for (x=0;x<width;x+=2,i++,j+=2) 
	  {	
	      /* "conservative" subsampling (see clause 3.1 of VM6.0) */
	      sub_data[i] = 
		  ((orig_data[j] == BINARY_ALPHA) ||
		   (orig_data[j+1] == BINARY_ALPHA) ||
		   (orig_data[j+width] == BINARY_ALPHA) ||
		   (orig_data[j+width+1] == BINARY_ALPHA))
		  ? BINARY_ALPHA : 0 ;
	  }
  }
 
  return;
}

