/**
  \class CDeltaPanel
  \brief Registers a panel that calculates a 'delta' image from the videosource
  
  This panel takes a CVideoDevice as input and performs a diff on 
  each frame and it's previous frame.
  
 */
#if HAVE_CONFIG_H
#include "config.h"
#endif

#include "DeltaPanel.h" 

#ifdef HAVE_INTELCPU
#include "video_asm.h"
#endif

/**
  \fn CDeltaPanel::CDeltaPanel(CVideoDevice *video)
  \brief Constructor. Registers as panel "delta.yuv"
 */
CDeltaPanel::CDeltaPanel(CVideoDevice *video)
	: CCamPanel("delta.yuv", "Video delta-YUV", YUV420)
{
   pVideo = video;
   pVideo->EnableYUV(true);
   SetSize(pVideo->GetSize());
}

// private

/**
  \fn void CDeltaPanel::Calculate(int n, void *dst, void *src1, void *src2)
  \brief Calculate the differential of 2 src pointers.
  \param n Number of pixels; this is assumed to be multiple of 4.
  \param dst Destination buffer.
  \param src1 Source buffer 1.
  \param src2 Source buffer 2. This is substracted from src1.
  
  This function calls an assembly routine to quickly calculate the 
  difference of 2 image buffers. The images are assumed to be of 
  equal dimension, grayscale with a linear range from 0..255. src2
  is substracted from src1, and 128 is added as a virtual null point.
  The pointers to the buffers are only checked for being not NULL.
 */
void CDeltaPanel::Calculate(int n, void *dst, void *src1, void *src2)
{
   if (dst == NULL || src1 == NULL || src2 == NULL) 
     return;

#ifdef HAVE_INTELCPU   
#ifdef HAVE_MMX
   calc_diff128_mmx(n, dst, src1, src2);
#else
   calc_diff128    (n, dst, src1, src2);
#endif
#else
   // Non-assembly version
   int i;
   uchar *d, *s1, *s2;
   
   d = (uchar *)dst;
   s1 = (uchar *)src1;
   s2 = (uchar *)src2;
     
   for (i = 0; i < n; i++) {
      *d = (128 + (*s1 >> 1) - (*s2 >> 1));
      d++;
      s1++;
      s2++;
   }
#endif
}

// public

/** 
  \fn virtual void CDeltaPanel::UpdatePanel()
  \brief Calculates differential of Y, U and V images.
 */

void CDeltaPanel::UpdatePanel()
{
   void *dst, *pold, *pnew;
   int pixels;
   
   pixels = image_w * image_h;
   if (IsVisible() || IsUsed()) {
     pnew = pVideo->GetY(0)->bits();
     pold = pVideo->GetY(1)->bits();
     dst  = ImgY.bits();
     Calculate(pixels,      dst, pnew, pold);

     pnew = pVideo->GetU(0)->bits();   
     pold = pVideo->GetU(1)->bits();
     dst  = ImgU.bits();
     Calculate(pixels >> 2, dst, pnew, pold);
     
     pnew = pVideo->GetV(0)->bits();   
     pold = pVideo->GetV(1)->bits();
     dst  = ImgV.bits();
     Calculate(pixels >> 2, dst, pnew, pold);

     emit Updated();
   }
}
   
