/* amidisplay.c, Amiga interface                                              */

/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */

/*
 * Disclaimer of Warranty
 *
 * These software programs are available to the user without any license fee or
 * royalty on an "as is" basis.  The MPEG Software Simulation Group disclaims
 * any and all warranties, whether express, implied, or statuary, including any
 * implied warranties or merchantability or of fitness for a particular
 * purpose.  In no event shall the copyright-holder be liable for any
 * incidental, punitive, or consequential damages of any kind whatsoever
 * arising from the use of these programs.
 *
 * This disclaimer of warranty extends to the user of these programs and user's
 * customers, employees, agents, transferees, successors, and assigns.
 *
 * The MPEG Software Simulation Group does not represent or warrant that the
 * programs furnished hereunder are free of infringement of any third-party
 * patents.
 *
 * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
 * are subject to royalty fees to patent holders.  Many of these patents are
 * general enough such that they are unavoidable regardless of implementation
 * design.
 *
 */

#ifdef DISPLAY

 /* the Xlib interface is closely modeled after
  * mpeg_play 2.0 by the Berkeley Plateau Research Group
  */

#include <stdio.h>
#include <stdlib.h>

#include "config.h"
#include "global.h"

#define CYBERGFXNAME     "cybergraphics.library"
#define CYBERGFXVERSION  40L

#include<string.h>
#include<dos.h>
#include<exec/exec.h>
#include<proto/exec.h>
#include<dos/dos.h>
#include<proto/dos.h>
#include<graphics/gfx.h>
#include<proto/graphics.h>
#include<intuition/intuition.h>
#include<proto/intuition.h>
#include<proto/asl.h>

#include<cybergraphics/cybergraphics.h>
#include<proto/cybergraphics.h>

/* Amiga prototypes */
struct Library *CyberGfxBase = NULL;
struct Window *displayWindow = NULL;
struct Screen *displayScreen = NULL;
struct RastPort *tempRastPort = NULL;
void *Ximage_Ptr, *Ximage_Ptr2;

void	c2p1x1_8_c5_ppc(void *chunky, void *bitplanes,
			int chunkyx, int chunkyy,
			int xoffset, int yoffset,
			int bitplanesize);
int __amiga_exit(void);
void __amiga_checkdisplay(void);
struct BitMap displayBitMap;
int displayIsOpen = FALSE;
int displayIsNative = TRUE;

/* private prototypes */
static void Display_Image _ANSI_ARGS_((void *Ximage_Ptr, unsigned char *Dithered_Image));
static void Dither_Frame _ANSI_ARGS_((unsigned char *src[]));
static void Dither_Top_Field _ANSI_ARGS_((unsigned char *src[], unsigned char *dst));
static void Dither_Bottom_Field _ANSI_ARGS_((unsigned char *src[], unsigned char *dst));
static void Dither_Top_Field420 _ANSI_ARGS_((unsigned char *src[],
                                      unsigned char *dst));
static void Dither_Bottom_Field420 _ANSI_ARGS_((unsigned char *src[],
                                      unsigned char *dst));


/* local data */
static unsigned char *Dithered_Image = NULL, *Dithered_Image2 = NULL, *Doubled_Image = NULL;

static unsigned char Y_Table[256+16];
static unsigned char Cb_Table[128+16];
static unsigned char Cr_Table[128+16];

static unsigned char Pixel[256];

/* connect to server, create and map window,
 * allocate colors and (shared) memory
 */
void Initialize_Display_Process(name)
char *name;
{
	int crv, cbu, cgu, cgv;
	int Y, Cb, Cr, R, G, B;
	int i;
	unsigned char *temp;

	displayIsOpen = TRUE;

	displayBitMap.Planes[0]=0;

	/* no mode selected, request one */

	if(Mode_ID == INVALID_ID)
	{
		struct ScreenModeRequester *sreq = NULL;

		if(sreq = (struct ScreenModeRequester *)AllocAslRequestTags(ASL_ScreenModeRequest,TAG_END))
		{
			if(AslRequest(sreq,TAG_END))
			{
				Mode_ID = sreq -> sm_DisplayID;
				printf("Next time, use option -m0x%lx\n",Mode_ID);
			}
			else
				Error("No valid screenmode selected\n");
			FreeAslRequest(sreq);
		}
	}

	/* open cybergraphics.library */

	if(CyberGfxBase = OpenLibrary(CYBERGFXNAME,CYBERGFXVERSION))
	{
		if(IsCyberModeID(Mode_ID))
			displayIsNative = FALSE;
	}

	/* setup automatically closing of the display */

	if(onbreak(&__amiga_exit)) Error("onbreak failed");
	if(atexit(&__amiga_checkdisplay)) Error("atexit failed");

	/* open screen */

	if(displayIsNative)
	{

		if( !(temp = (unsigned char *)AllocRaster(Coded_Picture_Width*Double_Pixels,Coded_Picture_Height*Double_Pixels*8)) )
			Error("AllocRaster failed");

		/* initialize bitmap */

		InitBitMap( &displayBitMap, 8, Coded_Picture_Width*Double_Pixels, Coded_Picture_Height*Double_Pixels);

		/* attach image data to bitmap */

		for( i=0; i<8;i++ )
			displayBitMap.Planes[i] = temp + i * RASSIZE (Coded_Picture_Width*Double_Pixels, Coded_Picture_Height*Double_Pixels);

		if(!(displayScreen = OpenScreenTags(NULL,
							SA_BitMap,&displayBitMap,
							SA_Width,Coded_Picture_Width*Double_Pixels,
							SA_Height,Coded_Picture_Height*Double_Pixels,
							SA_Title,"MPEG-2",
							SA_DisplayID,Mode_ID,
							SA_Depth,8,
							SA_ShowTitle,FALSE,
							TAG_END)))
			Error("OpenScreenTags failed");
	}
	else
	{
		if(!(displayScreen = OpenScreenTags(NULL,
							SA_Width,Coded_Picture_Width*Double_Pixels,
							SA_Height,Coded_Picture_Height*Double_Pixels,
							SA_Title,"MPEG-2",
							SA_DisplayID,Mode_ID,
							SA_Depth,8,
							SA_ShowTitle,FALSE,
							TAG_END)))
			Error("OpenScreenTags failed");
	}

	/* open window */

	if(!(displayWindow = OpenWindowTags(NULL,WA_CustomScreen,displayScreen,
						WA_Title,"MPEG-2 Display",
						WA_Width,Coded_Picture_Width*Double_Pixels,
						WA_Height,Coded_Picture_Height*Double_Pixels,
						WA_IDCMP,IDCMP_RAWKEY,
						WA_Backdrop,TRUE,
						WA_Borderless,TRUE,
						WA_RMBTrap,TRUE,
						WA_Activate,TRUE,
						WA_NewLookMenus,TRUE,
						WA_ScreenTitle,"MPEG-2",
						TAG_END)))
		Error("OpenWindowTags failed");

	//displayScreen = displayWindow -> WScreen;

	/* matrix coefficients */

	crv = Inverse_Table_6_9[matrix_coefficients][0];
	cbu = Inverse_Table_6_9[matrix_coefficients][1];
	cgu = Inverse_Table_6_9[matrix_coefficients][2];
	cgv = Inverse_Table_6_9[matrix_coefficients][3];

	/* allocate colors */

	/* color allocation:
	* i is the (internal) 8 bit color number, it consists of separate
	* bit fields for Y, U and V: i = (yyyyuuvv), we don't use yyyy=0000
	* and yyyy=1111, this leaves 32 colors for other applications
	*
	* the allocated colors correspond to the following Y, U and V values:
	* Y:   24, 40, 56, 72, 88, 104, 120, 136, 152, 168, 184, 200, 216, 232
	* U,V: -48, -16, 16, 48
	*
	* U and V values span only about half the color space; this gives
	* usually much better quality, although highly saturated colors can
	* not be displayed properly
	*
	* translation to R,G,B is implicitly done by the color look-up table
	*/

	for( i=0; i<256; i++) Pixel[i] = 0xff; /* clear to make sure that all colors are correctly freed */

	for( i=16; i<240; i++ )
	{
		/* color space conversion */

		Y  = 16*((i>>4)&15) + 8;
		Cb = 32*((i>>2)&3)  - 48;
		Cr = 32*(i&3)       - 48;

		Y = 76309 * (Y - 16); /* (255/219)*65536 */

		R = Clip[(Y + crv*Cr + 32768)>>16];
		G = Clip[(Y - cgu*Cb - cgv*Cr + 32768)>>16];
		B = Clip[(Y + cbu*Cb + 32786)>>16];

		SetRGB32(&displayScreen -> ViewPort,i,R<<24,G<<24,B<<24);
		Pixel[i] = i;
	}

	/* allocate temporary rastport */

	if(!(tempRastPort = malloc(sizeof(struct RastPort))))
		Error("malloc failed");
#if 0
	memcpy(tempRastPort,&displayScreen -> RastPort,sizeof(struct RastPort));
	tempRastPort -> Layer = NULL;
	tempRastPort -> BitMap = NULL;

	if(!(tempRastPort -> BitMap = AllocBitMap(((((Coded_Picture_Width*Double_Pixels)+15)>>4)<<1),1,((displayScreen -> RastPort).BitMap) -> Depth,NULL,NULL)))
		Error("AllocBitMap failed");
#endif
	/* allocate buffers */

	if(!(Dithered_Image = (unsigned char *)malloc((Coded_Picture_Width)*(Coded_Picture_Height))))
		Error("malloc failed");

	if(!progressive_sequence)
	{
		if(!(Dithered_Image2 = (unsigned char *)malloc((Coded_Picture_Width)*(Coded_Picture_Height))))
			Error("malloc failed");
	}

	if(!(Doubled_Image = (unsigned char *)malloc((Coded_Picture_Width*Double_Pixels)*(Coded_Picture_Height*Double_Pixels))))
		Error("malloc failed");
}

int __amiga_exit(void)
{
	fprintf(stderr,"CTRL-C received\n");
	return 1L;
}

void __amiga_checkdisplay(void)
{
	if(displayIsOpen) Terminate_Display_Process();
}

void Terminate_Display_Process()
{
	int i;

	if(Doubled_Image)
	{
		free(Doubled_Image);
		Doubled_Image = NULL;
	}
	if(Dithered_Image2)
	{
		free(Dithered_Image2);
		Dithered_Image2 = NULL;
	}
	if(Dithered_Image)
	{
		free(Dithered_Image);
		Dithered_Image = NULL;
	}
#if 0
	if(tempRastPort)
	{
		if(tempRastPort -> BitMap) FreeBitMap(tempRastPort -> BitMap);
		free(tempRastPort);
		tempRastPort = NULL;
	}
#endif

	for(i=0;i<256;i++) ReleasePen( (displayScreen -> ViewPort).ColorMap,Pixel[i]);

	if(displayWindow) CloseWindow(displayWindow);
	if(displayScreen) CloseScreen(displayScreen);

	if(displayBitMap.Planes[0])
	{
		FreeRaster(displayBitMap.Planes[0],Coded_Picture_Width*Double_Pixels,Coded_Picture_Height*Double_Pixels*8);
		displayBitMap.Planes[0]=NULL;
	}
	displayIsOpen = FALSE;

	/* close cybergraphics.library */

	if(CyberGfxBase)
	{
		CloseLibrary(CyberGfxBase);
		CyberGfxBase = NULL;
	}
}

int Frame_Count = NULL;

static void Display_Image(Ximage_Ptr,Dithered_Image)
void *Ximage_Ptr;
unsigned char *Dithered_Image;
{
	//static int count=0;
	//printf("display: %ld\r",count++);
	//fflush(stdout);

	/* scale picture to the double if -h is present */

	if(Double_Pixels == 2)
	{
		int i,j;
		unsigned char *dest_pointer = Doubled_Image;
		unsigned char *source_pointer = Dithered_Image;
		for(i=0;i<Coded_Picture_Height;i++)
		{
			for(j=0;j<Coded_Picture_Width;j++)
			{
				*(dest_pointer++)=*source_pointer;
				*(dest_pointer++)=*(source_pointer++);
			}
			source_pointer-=Coded_Picture_Width;
			for(j=0;j<Coded_Picture_Width;j++)
			{
				*(dest_pointer)++=*source_pointer;
				*(dest_pointer)++=*(source_pointer++);
			}
		}

		Dithered_Image = Doubled_Image;
	}

	if(displayIsNative)
		c2p1x1_8_c5_ppc(Dithered_Image,displayBitMap.Planes[0],
				Coded_Picture_Width*Double_Pixels,Coded_Picture_Height*Double_Pixels,
				0, 0,
				((Coded_Picture_Width*Double_Pixels)*(Coded_Picture_Height*Double_Pixels))/8);
	else
		WritePixelArray8(&displayScreen -> RastPort,0,0,(Coded_Picture_Width*Double_Pixels)-1,(Coded_Picture_Height*Double_Pixels)-1,Dithered_Image,&displayScreen -> RastPort);
}

void Display_Second_Field()
{
	if(Frame_Count)
	{
		Frame_Count--;
		return;
	}
	else
		Frame_Count = Frame_Skip;

  Display_Image(Ximage_Ptr2,Dithered_Image2);
}

/* 4x4 ordered dither
 *
 * threshold pattern:
 *   0  8  2 10
 *  12  4 14  6
 *   3 11  1  9
 *  15  7 13  5
 */

void Initialize_Dither_Matrix()
{
  int i, v;

  for (i=-8; i<256+8; i++)
  {
    v = i>>4;
    if (v<1)
      v = 1;
    else if (v>14)
      v = 14;
    Y_Table[i+8] = v<<4;
  }

  for (i=0; i<128+16; i++)
  {
    v = (i-40)>>4;
    if (v<0)
      v = 0;
    else if (v>3)
      v = 3;
    Cb_Table[i] = v<<2;
    Cr_Table[i] = v;
  }
}

void dither(src)
unsigned char *src[];
{
  /* should this test only the display flag, not progressive_sequence ? --CF */
  /* CHANGE 95/05/13: progressive_sequence -> progressive_frame */

	if(Frame_Count)
	{
		Frame_Count--;
		return;
	}
	else
		Frame_Count = Frame_Skip;

  if( progressive_frame || Display_Progressive_Flag)
    Dither_Frame(src);
  else
  {
    if ((picture_structure==FRAME_PICTURE && top_field_first) || picture_structure==BOTTOM_FIELD)
    {
      /* top field first */
      if (chroma_format==CHROMA420 && hiQdither)
      {
        Dither_Top_Field420(src,Dithered_Image);
        Dither_Bottom_Field420(src,Dithered_Image2);
      }
      else
      {
        Dither_Top_Field(src,Dithered_Image);
        Dither_Bottom_Field(src,Dithered_Image2);
      }
    }
    else
    {
      /* bottom field first */
      if (chroma_format==CHROMA420 && hiQdither)
      {
        Dither_Bottom_Field420(src,Dithered_Image);
        Dither_Top_Field420(src,Dithered_Image2);
      }
      else
      {
        Dither_Bottom_Field(src,Dithered_Image);
        Dither_Top_Field(src,Dithered_Image2);
      }
    }
  }

  Display_Image(Ximage_Ptr,Dithered_Image);
}

static void Dither_Frame(src)
unsigned char *src[];
{
  int i,j;
  int y,u,v;
  unsigned char *py,*pu,*pv,*dst;

  py = src[0];
  pu = src[1];
  pv = src[2];
  dst = Dithered_Image;

  for (j=0; j<Coded_Picture_Height; j+=4)
  {
    /* line j + 0 */
    for (i=0; i<Coded_Picture_Width; i+=4)
    {
      y = *py++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++ = Pixel[Y_Table[y]|Cb_Table[u]|Cr_Table[v]];
      y = *py++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++ = Pixel[Y_Table[y+8]|Cb_Table[u+8]|Cr_Table[v+8]];
      y = *py++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++ = Pixel[Y_Table[y+2]|Cb_Table[u+2]|Cr_Table[v+2]];
      y = *py++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++ = Pixel[Y_Table[y+10]|Cb_Table[u+10]|Cr_Table[v+10]];
    }

    if (chroma_format==CHROMA420)
    {
      pu -= Chroma_Width;
      pv -= Chroma_Width;
    }

    /* line j + 1 */
    for (i=0; i<Coded_Picture_Width; i+=4)
    {
      y = *py++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++ = Pixel[Y_Table[y+12]|Cb_Table[u+12]|Cr_Table[v+12]];
      y = *py++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++ = Pixel[Y_Table[y+4]|Cb_Table[u+4]|Cr_Table[v+4]];
      y = *py++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++ = Pixel[Y_Table[y+14]|Cb_Table[u+14]|Cr_Table[v+14]];
      y = *py++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++ = Pixel[Y_Table[y+6]|Cb_Table[u+6]|Cr_Table[v+6]];
    }

    /* line j + 2 */
    for (i=0; i<Coded_Picture_Width; i+=4)
    {
      y = *py++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++ = Pixel[Y_Table[y+3]|Cb_Table[u+3]|Cr_Table[v+3]];
      y = *py++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++ = Pixel[Y_Table[y+11]|Cb_Table[u+11]|Cr_Table[v+11]];
      y = *py++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++ = Pixel[Y_Table[y+1]|Cb_Table[u+1]|Cr_Table[v+1]];
      y = *py++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++ = Pixel[Y_Table[y+9]|Cb_Table[u+9]|Cr_Table[v+9]];
    }

    if (chroma_format==CHROMA420)
    {
      pu -= Chroma_Width;
      pv -= Chroma_Width;
    }

    /* line j + 3 */
    for (i=0; i<Coded_Picture_Width; i+=4)
    {
      y = *py++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++ = Pixel[Y_Table[y+15]|Cb_Table[u+15]|Cr_Table[v+15]];
      y = *py++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++ = Pixel[Y_Table[y+7]|Cb_Table[u+7]|Cr_Table[v+7]];
      y = *py++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++ = Pixel[Y_Table[y+13]|Cb_Table[u+13]|Cr_Table[v+13]];
      y = *py++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++ = Pixel[Y_Table[y+5]|Cb_Table[u+5]|Cr_Table[v+5]];
    }
  }

}

static void Dither_Top_Field(src,dst)
unsigned char *src[];
unsigned char *dst;
{
  int i,j;
  int y,Y2,u,v;
  unsigned char *py,*Y2_ptr,*pu,*pv,*dst2;

  py = src[0];
  Y2_ptr = src[0] + (Coded_Picture_Width<<1);
  pu = src[1];
  pv = src[2];
  dst2 = dst + Coded_Picture_Width;

  for (j=0; j<Coded_Picture_Height; j+=4)
  {
    /* line j + 0, j + 1 */
    for (i=0; i<Coded_Picture_Width; i+=4)
    {
      y = *py++;
      Y2 = *Y2_ptr++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++  = Pixel[Y_Table[y]|Cb_Table[u]|Cr_Table[v]];
      *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+12]|Cb_Table[u+12]|Cr_Table[v+12]];

      y = *py++;
      Y2 = *Y2_ptr++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++  = Pixel[Y_Table[y+8]|Cb_Table[u+8]|Cr_Table[v+8]];
      *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+4]|Cb_Table[u+4]|Cr_Table[v+4]];

      y = *py++;
      Y2 = *Y2_ptr++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++  = Pixel[Y_Table[y+2]|Cb_Table[u+2]|Cr_Table[v+2]];
      *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+14]|Cb_Table[u+14]|Cr_Table[v+14]];

      y = *py++;
      Y2 = *Y2_ptr++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++  = Pixel[Y_Table[y+10]|Cb_Table[u+10]|Cr_Table[v+10]];
      *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+6]|Cb_Table[u+6]|Cr_Table[v+6]];
    }

    py += Coded_Picture_Width;

    if (j!=(Coded_Picture_Height-4))
      Y2_ptr += Coded_Picture_Width;
    else
      Y2_ptr -= Coded_Picture_Width;

    dst += Coded_Picture_Width;
    dst2 += Coded_Picture_Width;

    if (chroma_format==CHROMA420)
    {
      pu -= Chroma_Width;
      pv -= Chroma_Width;
    }
    else
    {
      pu += Chroma_Width;
      pv += Chroma_Width;
    }

    /* line j + 2, j + 3 */
    for (i=0; i<Coded_Picture_Width; i+=4)
    {
      y = *py++;
      Y2 = *Y2_ptr++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++  = Pixel[Y_Table[y+3]|Cb_Table[u+3]|Cr_Table[v+3]];
      *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+15]|Cb_Table[u+15]|Cr_Table[v+15]];

      y = *py++;
      Y2 = *Y2_ptr++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++  = Pixel[Y_Table[y+11]|Cb_Table[u+11]|Cr_Table[v+11]];
      *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+7]|Cb_Table[u+7]|Cr_Table[v+7]];

      y = *py++;
      Y2 = *Y2_ptr++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++  = Pixel[Y_Table[y+1]|Cb_Table[u+1]|Cr_Table[v+1]];
      *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+13]|Cb_Table[u+13]|Cr_Table[v+13]];

      y = *py++;
      Y2 = *Y2_ptr++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++  = Pixel[Y_Table[y+9]|Cb_Table[u+9]|Cr_Table[v+9]];
      *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+5]|Cb_Table[u+5]|Cr_Table[v+5]];
    }

    py += Coded_Picture_Width;
    Y2_ptr += Coded_Picture_Width;
    dst += Coded_Picture_Width;
    dst2 += Coded_Picture_Width;
    pu += Chroma_Width;
    pv += Chroma_Width;
  }
}

static void Dither_Bottom_Field(src,dst)
unsigned char *src[];
unsigned char *dst;
{
  int i,j;
  int y,Y2,u,v;
  unsigned char *py,*Y2_ptr,*pu,*pv,*dst2;

  py = src[0] + Coded_Picture_Width;
  Y2_ptr = py;
  pu = src[1] + Chroma_Width;
  pv = src[2] + Chroma_Width;
  dst2 = dst + Coded_Picture_Width;

  for (j=0; j<Coded_Picture_Height; j+=4)
  {
    /* line j + 0, j + 1 */
    for (i=0; i<Coded_Picture_Width; i+=4)
    {
      y = *py++;
      Y2 = *Y2_ptr++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++  = Pixel[Y_Table[((y+Y2)>>1)]|Cb_Table[u]|Cr_Table[v]];
      *dst2++ = Pixel[Y_Table[Y2+12]|Cb_Table[u+12]|Cr_Table[v+12]];

      y = *py++;
      Y2 = *Y2_ptr++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++  = Pixel[Y_Table[((y+Y2)>>1)+8]|Cb_Table[u+8]|Cr_Table[v+8]];
      *dst2++ = Pixel[Y_Table[Y2+4]|Cb_Table[u+4]|Cr_Table[v+4]];

      y = *py++;
      Y2 = *Y2_ptr++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++  = Pixel[Y_Table[((y+Y2)>>1)+2]|Cb_Table[u+2]|Cr_Table[v+2]];
      *dst2++ = Pixel[Y_Table[Y2+14]|Cb_Table[u+14]|Cr_Table[v+14]];

      y = *py++;
      Y2 = *Y2_ptr++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++  = Pixel[Y_Table[((y+Y2)>>1)+10]|Cb_Table[u+10]|Cr_Table[v+10]];
      *dst2++ = Pixel[Y_Table[Y2+6]|Cb_Table[u+6]|Cr_Table[v+6]];
    }

    if (j==0)
      py -= Coded_Picture_Width;
    else
      py += Coded_Picture_Width;

    Y2_ptr += Coded_Picture_Width;
    dst += Coded_Picture_Width;
    dst2 += Coded_Picture_Width;

    if (chroma_format==CHROMA420)
    {
      pu -= Chroma_Width;
      pv -= Chroma_Width;
    }
    else
    {
      pu += Chroma_Width;
      pv += Chroma_Width;
    }

    /* line j + 2. j + 3 */
    for (i=0; i<Coded_Picture_Width; i+=4)
    {
      y = *py++;
      Y2 = *Y2_ptr++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++  = Pixel[Y_Table[((y+Y2)>>1)+3]|Cb_Table[u+3]|Cr_Table[v+3]];
      *dst2++ = Pixel[Y_Table[Y2+15]|Cb_Table[u+15]|Cr_Table[v+15]];

      y = *py++;
      Y2 = *Y2_ptr++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++  = Pixel[Y_Table[((y+Y2)>>1)+11]|Cb_Table[u+11]|Cr_Table[v+11]];
      *dst2++ = Pixel[Y_Table[Y2+7]|Cb_Table[u+7]|Cr_Table[v+7]];

      y = *py++;
      Y2 = *Y2_ptr++;
      u = *pu++ >> 1;
      v = *pv++ >> 1;
      *dst++  = Pixel[Y_Table[((y+Y2)>>1)+1]|Cb_Table[u+1]|Cr_Table[v+1]];
      *dst2++ = Pixel[Y_Table[Y2+13]|Cb_Table[u+13]|Cr_Table[v+13]];

      y = *py++;
      Y2 = *Y2_ptr++;
      if (chroma_format==CHROMA444)
      {
        u = *pu++ >> 1;
        v = *pv++ >> 1;
      }
      *dst++  = Pixel[Y_Table[((y+Y2)>>1)+9]|Cb_Table[u+9]|Cr_Table[v+9]];
      *dst2++ = Pixel[Y_Table[Y2+5]|Cb_Table[u+5]|Cr_Table[v+5]];
    }

    py += Coded_Picture_Width;
    Y2_ptr += Coded_Picture_Width;
    dst += Coded_Picture_Width;
    dst2 += Coded_Picture_Width;
    pu += Chroma_Width;
    pv += Chroma_Width;
  }
}

static void Dither_Top_Field420(src,dst)
unsigned char *src[];
unsigned char *dst;
{
  int i,j;
  int Y1,Cb1,Cr1,Y2,Cb2,Cr2;
  unsigned char *Y1_ptr,*Cb1_ptr,*Cr1_ptr,*Y2_ptr,*Cb2_ptr,*Cr2_ptr,*dst2;

  Y1_ptr = src[0];
  Cb1_ptr = src[1];
  Cr1_ptr = src[2];

  Y2_ptr = Y1_ptr + (Coded_Picture_Width<<1);
  Cb2_ptr = Cb1_ptr + (Chroma_Width<<1);
  Cr2_ptr = Cr1_ptr + (Chroma_Width<<1);

  dst2 = dst + Coded_Picture_Width;

  for (j=0; j<Coded_Picture_Height; j+=4)
  {
    /* line j + 0, j + 1 */
    for (i=0; i<Coded_Picture_Width; i+=4)
    {
      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      Cb1 = *Cb1_ptr++ >> 1;
      Cr1 = *Cr1_ptr++ >> 1;
      Cb2 = *Cb2_ptr++ >> 1;
      Cr2 = *Cr2_ptr++ >> 1;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)]|Cb_Table[Cb1]|Cr_Table[Cr1]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+12]|Cb_Table[((3*Cb1+Cb2)>>2)+12]
                                             |Cr_Table[((3*Cr1+Cr2)>>2)+12]];

      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+8]|Cb_Table[Cb1+8]|Cr_Table[Cr1+8]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+4]|Cb_Table[((3*Cb1+Cb2)>>2)+4]
                                            |Cr_Table[((3*Cr1+Cr2)>>2)+4]];

      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      Cb1 = *Cb1_ptr++ >> 1;
      Cr1 = *Cr1_ptr++ >> 1;
      Cb2 = *Cb2_ptr++ >> 1;
      Cr2 = *Cr2_ptr++ >> 1;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+2]|Cb_Table[Cb1+2]|Cr_Table[Cr1+2]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+14]|Cb_Table[((3*Cb1+Cb2)>>2)+14]
                                             |Cr_Table[((3*Cr1+Cr2)>>2)+14]];

      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+10]|Cb_Table[Cb1+10]|Cr_Table[Cr1+10]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+6]|Cb_Table[((3*Cb1+Cb2)>>2)+6]
                                            |Cr_Table[((3*Cr1+Cr2)>>2)+6]];
    }

    Y1_ptr += Coded_Picture_Width;

    if (j!=(Coded_Picture_Height-4))
      Y2_ptr += Coded_Picture_Width;
    else
      Y2_ptr -= Coded_Picture_Width;

    Cb1_ptr -= Chroma_Width;
    Cr1_ptr -= Chroma_Width;
    Cb2_ptr -= Chroma_Width;
    Cr2_ptr -= Chroma_Width;

    dst  += Coded_Picture_Width;
    dst2 += Coded_Picture_Width;

    /* line j + 2, j + 3 */
    for (i=0; i<Coded_Picture_Width; i+=4)
    {
      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      Cb1 = *Cb1_ptr++ >> 1;
      Cr1 = *Cr1_ptr++ >> 1;
      Cb2 = *Cb2_ptr++ >> 1;
      Cr2 = *Cr2_ptr++ >> 1;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+3]|Cb_Table[((Cb1+Cb2)>>1)+3]
                                            |Cr_Table[((Cr1+Cr2)>>1)+3]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+15]|Cb_Table[((Cb1+3*Cb2)>>2)+15]
                                             |Cr_Table[((Cr1+3*Cr2)>>2)+15]];

      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+11]|Cb_Table[((Cb1+Cb2)>>1)+11]
                                             |Cr_Table[((Cr1+Cr2)>>1)+11]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+7]|Cb_Table[((Cb1+3*Cb2)>>2)+7]
                                            |Cr_Table[((Cr1+3*Cr2)>>2)+7]];

      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      Cb1 = *Cb1_ptr++ >> 1;
      Cr1 = *Cr1_ptr++ >> 1;
      Cb2 = *Cb2_ptr++ >> 1;
      Cr2 = *Cr2_ptr++ >> 1;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+1]|Cb_Table[((Cb1+Cb2)>>1)+1]
                                            |Cr_Table[((Cr1+Cr2)>>1)+1]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+13]|Cb_Table[((Cb1+3*Cb2)>>2)+13]
                                             |Cr_Table[((Cr1+3*Cr2)>>2)+13]];

      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+9]|Cb_Table[((Cb1+Cb2)>>1)+9]
                                            |Cr_Table[((Cr1+Cr2)>>1)+9]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+5]|Cb_Table[((Cb1+3*Cb2)>>2)+5]
                                            |Cr_Table[((Cr1+3*Cr2)>>2)+5]];
    }

    Y1_ptr += Coded_Picture_Width;
    Y2_ptr += Coded_Picture_Width;
    Cb1_ptr += Chroma_Width;
    Cr1_ptr += Chroma_Width;
    if (j!=(Coded_Picture_Height-8))
    {
      Cb2_ptr += Chroma_Width;
      Cr2_ptr += Chroma_Width;
    }
    else
    {
      Cb2_ptr -= Chroma_Width;
      Cr2_ptr -= Chroma_Width;
    }
    dst += Coded_Picture_Width;
    dst2+= Coded_Picture_Width;
  }
}

static void Dither_Bottom_Field420(src,dst)
unsigned char *src[];
unsigned char *dst;
{
  int i,j;
  int Y1,Cb1,Cr1,Y2,Cb2,Cr2;
  unsigned char *Y1_ptr,*Cb1_ptr,*Cr1_ptr,*Y2_ptr,*Cb2_ptr,*Cr2_ptr,*dst2;

  Y2_ptr = Y1_ptr = src[0] + Coded_Picture_Width;
  Cb2_ptr = Cb1_ptr = src[1] + Chroma_Width;
  Cr2_ptr = Cr1_ptr = src[2] + Chroma_Width;

  dst2 = dst;

  for (j=0; j<Coded_Picture_Height; j+=4)
  {
    /* line j + 0, j + 1 */
    for (i=0; i<Coded_Picture_Width; i+=4)
    {
      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      Cb1 = *Cb1_ptr++ >> 1;
      Cr1 = *Cr1_ptr++ >> 1;
      Cb2 = *Cb2_ptr++ >> 1;
      Cr2 = *Cr2_ptr++ >> 1;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+15]|Cb_Table[((3*Cb1+Cb2)>>2)+15]
                                             |Cr_Table[((3*Cr1+Cr2)>>2)+15]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)]|Cb_Table[((Cb1+Cb2)>>1)]
                                          |Cr_Table[((Cr1+Cr2)>>1)]];

      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+7]|Cb_Table[((3*Cb1+Cb2)>>2)+7]
                                            |Cr_Table[((3*Cr1+Cr2)>>2)+7]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+8]|Cb_Table[((Cb1+Cb2)>>1)+8]
                                            |Cr_Table[((Cr1+Cr2)>>1)+8]];

      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      Cb1 = *Cb1_ptr++ >> 1;
      Cr1 = *Cr1_ptr++ >> 1;
      Cb2 = *Cb2_ptr++ >> 1;
      Cr2 = *Cr2_ptr++ >> 1;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+13]|Cb_Table[((3*Cb1+Cb2)>>2)+13]
                                             |Cr_Table[((3*Cr1+Cr2)>>2)+13]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+2]|Cb_Table[((Cb1+Cb2)>>1)+2]
                                            |Cr_Table[((Cr1+Cr2)>>1)+2]];

      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+5]|Cb_Table[((3*Cb1+Cb2)>>2)+5]
                                            |Cr_Table[((3*Cr1+Cr2)>>2)+5]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+10]|Cb_Table[((Cb1+Cb2)>>1)+10]
                                             |Cr_Table[((Cr1+Cr2)>>1)+10]];
    }

    if (j!=0)
      Y1_ptr += Coded_Picture_Width;
    else
      Y1_ptr -= Coded_Picture_Width;

    Y2_ptr += Coded_Picture_Width;

    Cb1_ptr -= Chroma_Width;
    Cr1_ptr -= Chroma_Width;
    Cb2_ptr -= Chroma_Width;
    Cr2_ptr -= Chroma_Width;

    if (j!=0)
      dst  += Coded_Picture_Width;

    dst2 += Coded_Picture_Width;

    /* line j + 2, j + 3 */
    for (i=0; i<Coded_Picture_Width; i+=4)
    {
      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      Cb1 = *Cb1_ptr++ >> 1;
      Cr1 = *Cr1_ptr++ >> 1;
      Cb2 = *Cb2_ptr++ >> 1;
      Cr2 = *Cr2_ptr++ >> 1;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+12]|Cb_Table[((Cb1+3*Cb2)>>2)+12]
                                             |Cr_Table[((Cr1+3*Cr2)>>2)+12]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+3]|Cb_Table[Cb2+3]
                                            |Cr_Table[Cr2+3]];

      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+4]|Cb_Table[((Cb1+3*Cb2)>>2)+4]
                                            |Cr_Table[((Cr1+3*Cr2)>>2)+4]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+11]|Cb_Table[Cb2+11]
                                             |Cr_Table[Cr2+11]];

      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      Cb1 = *Cb1_ptr++ >> 1;
      Cr1 = *Cr1_ptr++ >> 1;
      Cb2 = *Cb2_ptr++ >> 1;
      Cr2 = *Cr2_ptr++ >> 1;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+14]|Cb_Table[((Cb1+3*Cb2)>>2)+14]
                                             |Cr_Table[((Cr1+3*Cr2)>>2)+14]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+1]|Cb_Table[Cb2+1]
                                            |Cr_Table[Cr2+1]];

      Y1 = *Y1_ptr++;
      Y2 = *Y2_ptr++;
      *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+6]|Cb_Table[((Cb1+3*Cb2)>>2)+6]
                                            |Cr_Table[((Cr1+3*Cr2)>>2)+6]];
      *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+9]|Cb_Table[Cb2+9]
                                            |Cr_Table[Cr2+9]];
    }

    Y1_ptr += Coded_Picture_Width;
    Y2_ptr += Coded_Picture_Width;

    if (j!=0)
    {
      Cb1_ptr += Chroma_Width;
      Cr1_ptr += Chroma_Width;
    }
    else
    {
      Cb1_ptr -= Chroma_Width;
      Cr1_ptr -= Chroma_Width;
    }

    Cb2_ptr += Chroma_Width;
    Cr2_ptr += Chroma_Width;

    dst += Coded_Picture_Width;
    dst2+= Coded_Picture_Width;
  }

  Y2_ptr -= (Coded_Picture_Width<<1);
  Cb2_ptr -= (Chroma_Width<<1);
  Cr2_ptr -= (Chroma_Width<<1);

  /* dither last line */
  for (i=0; i<Coded_Picture_Width; i+=4)
  {
    Y1 = *Y1_ptr++;
    Y2 = *Y2_ptr++;
    Cb1 = *Cb1_ptr++ >> 1;
    Cr1 = *Cr1_ptr++ >> 1;
    Cb2 = *Cb2_ptr++ >> 1;
    Cr2 = *Cr2_ptr++ >> 1;
    *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+15]|Cb_Table[((3*Cb1+Cb2)>>2)+15]
                                           |Cr_Table[((3*Cr1+Cr2)>>2)+15]];

    Y1 = *Y1_ptr++;
    Y2 = *Y2_ptr++;
    *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+7]|Cb_Table[((3*Cb1+Cb2)>>2)+7]
                                          |Cr_Table[((3*Cr1+Cr2)>>2)+7]];

    Y1 = *Y1_ptr++;
    Y2 = *Y2_ptr++;
    Cb1 = *Cb1_ptr++ >> 1;
    Cr1 = *Cr1_ptr++ >> 1;
    Cb2 = *Cb2_ptr++ >> 1;
    Cr2 = *Cr2_ptr++ >> 1;
    *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+13]|Cb_Table[((3*Cb1+Cb2)>>2)+13]
                                           |Cr_Table[((3*Cr1+Cr2)>>2)+13]];

    Y1 = *Y1_ptr++;
    Y2 = *Y2_ptr++;
    *dst++  = Pixel[Y_Table[((3*Y1+Y2)>>2)+5]|Cb_Table[((3*Cb1+Cb2)>>2)+5]
                                          |Cr_Table[((3*Cr1+Cr2)>>2)+5]];
    }

}

#define twomerges1(a, b, c, d, shift, mask) \
	{ \
	temp1 = b; \
	temp2 = d; \
	temp1 >>= shift; \
	temp2 >>= shift; \
	temp1 ^= a; \
	temp2 ^= c; \
	temp1 &= mask; \
	temp2 &= mask; \
	a ^= temp1; \
	c ^= temp2; \
	temp1 <<= shift; \
	temp2 <<= shift; \
	b ^= temp1; \
	d ^= temp2; \
	}

#define twomerges2(a, b, c, d, shift, mask) \
	{ \
	temp1 = (a ^ (b >> shift)) & mask; \
	temp2 = (c ^ (d >> shift)) & mask; \
	a ^= temp1; \
	c ^= temp2; \
	b ^= temp1 << shift; \
	d ^= temp2 << shift; \
	}

void	c2p1x1_8_c5_ppc(void *chunky, void *bitplanes,
			int chunkyx, int chunkyy,
			int xoffset, int yoffset,
			int bitplanesize)
{
typedef unsigned long ULONG;

	ULONG	*c;
	ULONG	temp1, temp2;
	ULONG	*p0, *p1, *p2, *p3, *p4, *p5, *p6, *p7;
	ULONG	d0, d1, d2, d3, d4, d5, d6, d7;
	ULONG	t0, t1, t2, t3, t4, t5, t6, t7;
	int	i;

	c = (ULONG *) chunky;
	p0 = (ULONG *) (&(((char *) bitplanes)[yoffset * chunkyx >> 3]));
	p1 = (ULONG *) (&(((char *) p0)[bitplanesize]));
	p2 = (ULONG *) (&(((char *) p1)[bitplanesize]));
	p3 = (ULONG *) (&(((char *) p2)[bitplanesize]));
	p4 = (ULONG *) (&(((char *) p3)[bitplanesize]));
	p5 = (ULONG *) (&(((char *) p4)[bitplanesize]));
	p6 = (ULONG *) (&(((char *) p5)[bitplanesize]));
	p7 = (ULONG *) (&(((char *) p6)[bitplanesize]));

	i = chunkyx * chunkyy / (sizeof (ULONG) * 8);

	d0 = *c++;
	d1 = *c++;
	d2 = *c++;
	d3 = *c++;
	d4 = *c++;
	d5 = *c++;
	d6 = *c++;
	d7 = *c++;

	twomerges1(d0, d4, d1, d5, 16, 0x0000ffff);
	twomerges1(d2, d6, d3, d7, 16, 0x0000ffff);

	twomerges1(d0, d2, d1, d3, 8, 0x00ff00ff);
	twomerges1(d4, d6, d5, d7, 8, 0x00ff00ff);

	twomerges1(d0, d1, d2, d3, 4, 0x0f0f0f0f);
	twomerges1(d4, d5, d6, d7, 4, 0x0f0f0f0f);

	twomerges1(d0, d4, d1, d5, 2, 0x33333333);
	twomerges1(d2, d6, d3, d7, 2, 0x33333333);

	twomerges1(d0, d2, d1, d3, 1, 0x55555555);
	twomerges1(d4, d6, d5, d7, 1, 0x55555555);

	t0 = d7;
	t1 = d5;
	t2 = d3;
	t3 = d1;
	t4 = d6;
	t5 = d4;
	t6 = d2;
	t7 = d0;

	while (--i)
	{
		d0 = *c++;
		d1 = *c++;
		d2 = *c++;
		d3 = *c++;
		d4 = *c++;
		d5 = *c++;
		d6 = *c++;
		d7 = *c++;

		*p0++ = t0;

		twomerges1(d0, d4, d1, d5, 16, 0x0000ffff);
		twomerges1(d2, d6, d3, d7, 16, 0x0000ffff);

		*p1++ = t1;

		twomerges1(d0, d2, d1, d3, 8, 0x00ff00ff);
		twomerges1(d4, d6, d5, d7, 8, 0x00ff00ff);

		*p2++ = t2;

		twomerges1(d0, d1, d2, d3, 4, 0x0f0f0f0f);
		twomerges1(d4, d5, d6, d7, 4, 0x0f0f0f0f);

		*p3++ = t3;

		twomerges1(d0, d4, d1, d5, 2, 0x33333333);
		twomerges1(d2, d6, d3, d7, 2, 0x33333333);

		*p4++ = t4;

		twomerges1(d0, d2, d1, d3, 1, 0x55555555);
		twomerges1(d4, d6, d5, d7, 1, 0x55555555);

		*p5++ = t5;
		*p6++ = t6;
		*p7++ = t7;

		t0 = d7;
		t1 = d5;
		t2 = d3;
		t3 = d1;
		t4 = d6;
		t5 = d4;
		t6 = d2;
		t7 = d0;

	}

	*p0++ = t0;
	*p1++ = t1;
	*p2++ = t2;
	*p3++ = t3;
	*p4++ = t4;
	*p5++ = t5;
	*p6++ = t6;
	*p7++ = t7;

}

#endif
