/* $Id: QMUtils.c,v 1.21 1998/03/13 20:05:20 hatrack Exp $ */
/****************************************************************************/
/*   MPEG4 Visual Texture Coding (VTC) Mode Software                        */
/*                                                                          */
/*   This software was developed by                                         */
/*   Sarnoff Coporation                   and    Texas Instruments          */
/*   Iraj Sodagar   (iraj@sarnoff.com)           Jie Liang (liang@ti.com)   */
/*   Hung-Ju Lee    (hjlee@sarnoff.com)                                     */
/*   Paul Hatrack   (hatrack@sarnoff.com)                                   */
/*   Shipeng Li     (shipeng@sarnoff.com)                                   */
/*   Bing-Bing Chai (bchai@sarnoff.com)                                     */
/*                                                                          */
/* In the course of development of the MPEG-4 standard. This software       */
/* module is an implementation of a part of one or more MPEG-4 tools as     */
/* specified by the MPEG-4 standard.                                        */
/*                                                                          */
/* The copyright of this software belongs to ISO/IEC. ISO/IEC gives use     */
/* of the MPEG-4 standard free license to use this  software module or      */
/* modifications thereof for hardware or software products claiming         */
/* conformance to the MPEG-4 standard.                                      */
/*                                                                          */
/* Those intending to use this software module in hardware or software      */
/* products are advised that use may infringe existing  patents. The        */
/* original developers of this software module and their companies, the     */
/* subsequent editors and their companies, and ISO/IEC have no liability    */
/* and ISO/IEC have no liability for use of this software module or         */
/* modification thereof in an implementation.                               */
/*                                                                          */
/* Permission is granted to MPEG memebers to use, copy, modify,             */
/* and distribute the software modules ( or portions thereof )              */
/* for standardization activity within ISO/IEC JTC1/SC29/WG11.              */
/*                                                                          */
/* Copyright (C) 1998  Sarnoff Coporation and Texas Instruments             */ 
/****************************************************************************/

/************************************************************/
/*     Sarnoff Very Low Bit Rate Still Image Coder          */
/*     Copyright 1995, 1996, 1997, 1998 Sarnoff Corporation */
/************************************************************/

#include <stdio.h>
#include "dataStruct.h"
#include "globals.h"
#include "states.h"
#include "QMUtils.h"
#include "errorHandler.h"

/* 
   Function Name
   -------------
   Int findChild(Int x, Int y, Int xc[], Int yc[])

   Arguments 
   ---------
   Int x, Int y - Index of wavelet coefficient (row, col) to check.
   Int xc[], Int yc[] - Indices of the (maximum of 4) children of (x,y).

   Description
   -----------
   findChild returns the number of children of (x,y). If there are 
   children it puts their indices in (xc, yc).
   
   mzte_codec.dcWidth, mzte_codec.dcHeight, mzte_codec.SPlayer.width, and 
   mzte_codec.SPlayer.height must all be set to their proper values.

   Functions Called
   ----------------
   none

   Return Value
   ------------
   The number of children of (x,y).

   Source File
   -----------
   QMUtils.c
*/

Int findChild(Int x, Int y, Int xc[], Int yc[], Int c)
{
   Int numChildren;

   if (x < mzte_codec.dcWidth && y < mzte_codec.dcHeight)
   {
     /*------------------- DC Band ---------------------*/ 
     numChildren = 3;

     xc[0] = x + mzte_codec.dcWidth;
     yc[0] = y;
     
     xc[1] = x;
     yc[1] = y + mzte_codec.dcHeight;
     
     xc[2] = x + mzte_codec.dcWidth;
     yc[2] = y + mzte_codec.dcHeight;
   }
   else if((x *= 2) < mzte_codec.SPlayer[c].width && 
	   (y *= 2) < mzte_codec.SPlayer[c].height) 
   { 
     /*------------------- Non-Leaf AC Band ---------------------*/ 
     numChildren = 4;
     
     xc[0] = x;
     yc[0] = y;
     
     xc[1] = x+1;
     yc[1] = y  ;
     
     xc[2] = x  ;
     yc[2] = y+1;
     
     xc[3] = x+1;
     yc[3] = y+1;
   }
   else
     /*------------------- Leaf AC Band ---------------------*/ 
     numChildren = 0;
	
   return numChildren;
}


/* 
   Function Name
   -------------
   Int isIndexInRootBands(Int x, Int y)

   Arguments 
   ---------
   Int x, Int y - Index of wavelet coefficient (row, col) to check.

   Description
   -----------
   isIndexInRootBands checks if (x,y) is in a root band (first three AC
   bands which aren't leafs).
   
   mzte_codec.dcWidth, mzte_codec.dcHeight, mzte_codec.SPlayer.width, and 
   mzte_codec.SPlayer.height must all be set to their proper values.

   Functions Called
   ----------------
   none

   Return Value
   ------------
   The number of children of (x,y).

   Source File
   -----------
   QMUtils.c
*/

Int isIndexInRootBands(Int x, Int y, Int c)
{  
  Int x1, x2, y1, y2;

  x1 = mzte_codec.dcWidth<<1;
  x2 = mzte_codec.SPlayer[c].width>>1;
  y1 = mzte_codec.dcHeight<<1;
  y2 = mzte_codec.SPlayer[c].height>>1;

  return x < MIN(x1,x2) && y < MIN(y1,y2) 
    && (x >= mzte_codec.dcWidth || y >= mzte_codec.dcHeight);
}


/* 
   Function Name
   -------------
   Void markCoeff(Int x, Int y, UChar valuedDes)

   Arguments 
   ---------
   Int x, Int y - Index of wavelet coefficient (row, col) to mark.
   UChar valuedDes - Flag for existence of non-zero descendents at
     (x,y). 0 = all descendents are zero, 1 = some descendents are non-zero.

   Description
   -----------
   Mark type of current coefficient.

   Functions Called
   ----------------
   none

   Return Value
   ------------
   none

   Source File
   -----------
   QMUtils.c
*/

Void markCoeff(Int x, Int y, UChar valuedDes, Int c)
{		
  if (COEFF_STATE(x,y,c) == S_LEAF || COEFF_STATE(x,y,c) == S_RLEAF)
  {
    if (COEFF_VAL(x,y,c))
      COEFF_TYPE(x,y,c) = VLEAF;
    else
      COEFF_TYPE(x,y,c) = ZLEAF;
  }
  else
  {
    if (COEFF_VAL(x,y,c))
    {
      if (valuedDes)
	COEFF_TYPE(x,y,c) = VAL;
      else
	COEFF_TYPE(x,y,c) = VZTR;
    }
    else
    {
      if (valuedDes)
	COEFF_TYPE(x,y,c) = IZ;
      else
	COEFF_TYPE(x,y,c) = ZTR;
    }
  }
}

/* 
   Function Name
   -------------
   Void updateState(Int x, Int y, Int type)

   Arguments 
   ---------
   Int x, Int y - Index of wavelet coefficient (row, col) to mark.

   Description
   -----------
   Update the state of current coefficient.

   Functions Called
   ----------------
   none

   Return Value
   ------------
   none

   Source File
   -----------
   QMUtils.c
*/

Void updateState(Int x, Int y, Int type, Int c)
{
  switch(COEFF_STATE(x,y,c))
  {
    case S_ROOT:
    case S_NZ:
      if (COEFF_TYPE(x,y,c) == VAL)
	COEFF_STATE(x,y,c)=S_RVAL;
      else if (COEFF_TYPE(x,y,c) == VZTR)
	COEFF_STATE(x,y,c)=S_RVZTR;
      break;      
    case S_LEAF:
      if (COEFF_VAL(x,y,c))
	COEFF_STATE(x,y,c)=S_RLEAF;
      break;
    case S_RVZTR:
      if (COEFF_TYPE(x,y,c) == VAL || COEFF_TYPE(x,y,c) == IZ)
	COEFF_STATE(x,y,c)=S_RVAL;
      break;
    case S_RVAL:
    case S_RLEAF:
    case S_DC:
    default:
      break;
  }

#ifdef _IMPLIED_SKIP_IZ_
  /* update skip mode */
  if (COEFF_SKIP(x,y,c)==SKIP_TNYC || COEFF_SKIP(x,y,c)==SKIP_ZTR)
  {
    if (COEFF_TYPE(x,y,c)==IZ)
      COEFF_SKIP(x,y,c) = SKIP_IZ;
    else
      COEFF_SKIP(x,y,c) = SKIP_ZTR;
  }
#endif

}


/* 
   Function Name
   -------------
   Void updateCoeffAndDescState(Int x, Int y)

   Arguments 
   ---------
   Int x, Int y - Index of wavelet coefficient (row, col) to mark.

   Description
   -----------
   Update the state of coefficient at (x,y) and all of it's descendents. 
   Uses recursion to accomplish this.

   Functions Called
   ----------------
   findChild
   updateCoeffAndDescState (recursive call)
   updateState

   Return Value
   ------------
   none.

   Source File
   -----------
   QMUtils.c
*/

Void updateCoeffAndDescState(Int x, Int y, Int c)
{
  Int i;
  Int xc[4], yc[4]; /* coords of children */
  Int nc; /* number of children */

  /* Are we at a leaf? */
  if ((nc = findChild(x, y, xc, yc, c)) > 0)
  {
    /* No - mark descendents in all branches */
    for (i = 0; i < nc; ++i)
      updateCoeffAndDescState(xc[i], yc[i], c);
  }
  
  /* Updates state in coeffTable */
  updateState(x, y, COEFF_TYPE(x, y, c), c);
}

/* 
   Function Name
   -------------
   Void spatialLayerChangeUpdate()

   Arguments 
   ---------
   none.

   Description
   -----------
   Update the state of leaf coefficients when the spatial layer changes.
   Call right *after* spatial layer has increased. It is assummed that
   the increase was a doubling of the size (three more AC bands).

   Functions Called
   ----------------
   none.

   Return Value
   ------------
   none.

   Source File
   -----------
   QMUtils.c
*/

Void spatialLayerChangeUpdate(Int c)
{  
  Int x, y;
  Int oldWidth, oldHeight;
  Int xLeafStart, yLeafStart;

  noteDetail("Updating new coefficients in spatial layer for col %d....",c);

  oldWidth  = mzte_codec.SPlayer[c].width>>1;
  oldHeight = mzte_codec.SPlayer[c].height>>1; 

  xLeafStart = oldWidth>>1;
  yLeafStart = oldHeight>>1; 
 
  /* loop through leaf coefficients */
  /* HL */
  for (y = 0; y < yLeafStart; ++y)
    for (x = xLeafStart; x < oldWidth; ++x)
    {
      /* update state */
      if (COEFF_STATE(x,y,c) == S_LEAF)
	COEFF_STATE(x,y,c) = S_NZ;
      else if (COEFF_STATE(x,y,c) == S_RLEAF)
	COEFF_STATE(x,y,c) = S_RVZTR;
      else
	errorHandler("Non-leaf state (%d) for leaf coefficient at"\
		     "(x=%d, y=%d).", 
		     COEFF_STATE(x, y,c), x, y);
    }

  /* LH */
  for (y = yLeafStart; y < oldHeight; ++y)
    for (x = 0; x < xLeafStart; ++x)
    {
      /* update state */
      if (COEFF_STATE(x, y,c) == S_LEAF)
	COEFF_STATE(x, y,c) = S_NZ;
      else if (COEFF_STATE(x, y,c) == S_RLEAF)
	COEFF_STATE(x, y,c) = S_RVZTR;
      else
	errorHandler("Non-leaf state (%d) for leaf coefficient at"\
		     "(x=%d, y=%d).", 
		     COEFF_STATE(x, y,c), x, y);
    }
  
  /* HH */
  for (y = yLeafStart; y < oldHeight; ++y)
    for (x = xLeafStart; x < oldWidth; ++x)
    {
      /* update state */
      if (COEFF_STATE(x, y,c) == S_LEAF)
	COEFF_STATE(x, y, c) = S_NZ;
      else if (COEFF_STATE(x, y,c) == S_RLEAF)
	COEFF_STATE(x, y,c) = S_RVZTR;
      else
	errorHandler("Non-leaf state (%d) for leaf coefficient at"\
		     "(x=%d, y=%d).", 
		     COEFF_STATE(x, y,c), x, y);
    }

  noteDetail("Completed updating new coefficients in spatial layer.");

}


Int coordToSpatialLev(Int x, Int y, Int c)
{
  Int sx, sy;
  Int k;

  /* size for spatial layer 0 */
  sx =
    (mzte_codec.width>> (c>0)) >> (mzte_codec.spatial_scalability_levels-1);
  sy = 
    (mzte_codec.height >> (c>0)) >> (mzte_codec.spatial_scalability_levels-1);


  for (k = 0; ; ++k)
  {
    if (x < sx && y < sy)
      return k;

    sx <<= 1;
    sy <<= 1;
  }
}
