/* 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>

#ifdef STORM
#include <clib/cybergraphics_protos.h>
#include <powerpc/powerpc.h>
#include <clib/powerpc_protos.h>
int bus_MHz=60;
int bus_clock=60000000;
double tb_scale_lo;
double tb_scale_hi;
extern int wb;
#else
#include<proto/cybergraphics.h>
#endif

struct RastPort *rp;

#ifdef STORM
#include <clib/cybergraphics_protos.h>
#include <clib/chunkyppc_protos.h>
struct Library *ChunkyPPCBase;
#else
#include<proto/cybergraphics.h>
#endif

#ifdef STORM
struct TagItem helpbuf[3];
int direct=1;
UBYTE *address;
int bpr;
int opt=0;
#endif

/* 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
 */

#ifndef STORM
struct Library *TimerBase = NULL;
struct timerequest *TimerIO = NULL;
struct MsgPort *IDCMP = NULL;
struct MsgPort *TimerMP = 0;
#else
void ppctimer(unsigned int[2]);
#endif

void IO_StartupTimer (void)
{
// Ripped out of sourcecode of AmiHeretic...
#ifdef STORM
 struct TagItem ppcinfo[2]={GETINFO_BUSCLOCK,0,0,0};
 GetInfo(ppcinfo);
 bus_MHz=ppcinfo[0].ti_Data/(1000*1000);
 bus_clock=ppcinfo[0].ti_Data;
 tb_scale_lo = ((double)(bus_clock >> 2)) / 35.0;
 tb_scale_hi = (4.294967296E9 / (double)(bus_clock >> 2)) * 35.0;
#else
    TimerMP = CreateMsgPort();
    if (!TimerMP)
        I_Error("I_InitTimer: Can't create timer message port");
    TimerIO = (struct timerequest *)CreateExtIO(TimerMP, sizeof(struct timerequest));
    if (!TimerIO)
        I_Error("I_InitTimer: Can't create timer IO");

    if (OpenDevice((UBYTE *)TIMERNAME, UNIT_MICROHZ, (struct IORequest *)TimerIO, 0l) != 0)
        I_Error("I_InitTimer: Can't open timer.device");

    TimerBase = (struct Library *)TimerIO->tr_node.io_Device;
#endif
}

void IO_ShutdownTimer(void)
{
// Ripped out of sourcecode of AmiHeretic...
#ifndef STORM
   if (TimerIO) {
        CloseDevice((struct IORequest *)TimerIO);
        DeleteExtIO((struct IORequest *)TimerIO);
        TimerIO = 0;
        TimerBase = 0;
    }

    if (TimerMP) {
        DeleteMsgPort(TimerMP);
        TimerMP = 0;
    }
#endif
}

long frames=0;
long secs=0;

#ifdef STORM
void video_do_fps()
{
// Ripped out of Source-Code of AmiHeretic, using 68k source
// if STORM is not defined... small mod's, as mpeg2decode
// uses intuition, and not rtgmaster which AmiHeretic is using...
  int x;
  static unsigned int start_time[2] = {0, 0};
  unsigned int end_time[2];
  char msg[4];

  ppctimer (end_time);
  if (end_time[1] >= start_time[1])
    x = (((end_time[1] - start_time[1]) << 2) / bus_MHz);
  else
    x = (((end_time[1] - start_time[1]) << 2) / bus_MHz + 1000000);
  if (x != 0) {
    x = (1000000 + (x >> 1)) / x;   /* round to nearest */
    msg[0] = (x % 1000) / 100 + '0';
    msg[1] = (x % 100) / 10 + '0';
    msg[2] = (x % 10) + '0';
    msg[3] = '\0';
    Move(rp,Coded_Picture_Width*Double_Pixels-24,6);
    Text(rp,msg,strlen(msg));
  }
  start_time[1] = end_time[1];
  frames+=x;
  secs+=1;
}
#else
void video_do_fps()
{
    static struct timeval start;
    static int init = 0;
    struct timeval end, tmp;
    char msg[4];
    unsigned long x;

    if (init == 0) {
        init = 1;
        GetSysTime(&start);
        return;
    }

    GetSysTime(&end);
    SubTime((struct timeval *)&end, (struct timeval *)&start);
    x = (unsigned long)((float)frame++/(float)end.tv_secs);

    msg[0] = (x % 1000) / 100 + '0';
    msg[1] = (x % 100) / 10 + '0';
    msg[2] = (x % 10) + '0';
    msg[3] = '\0';

    Move(rp,Coded_Picture_Width*Double_Pixels-24,6);
    Text(rp,msg,strlen(msg));
    frames+=x;
    secs+=1;
}
#endif

#ifdef STORM
struct TagItem asltags[]=
{0,0
};
UBYTE *colarray1;
unsigned long WBColorTable[3*256+2],ColorTable[3*256+2];
UBYTE transtable[256];
UBYTE *wbcolors;
#include <graphics/rastport.h>
int pen_obtained=0;
void LoadRGBRtg(struct Window *MyWindow, ULONG Table[])
{
        // Slightly modified version of the rtgmaster function,
        // taken out of rtgmaster source code...
        struct TagItem EmptyTags[] =
        {
                TAG_DONE,0
        };
        

        int i,r,g,b;
        unsigned char *p;
        struct ViewPort *VPort;
        struct Window *Window;
        struct ColorMap *ColorMap;

        ColorMap = MyWindow->WScreen->ViewPort.ColorMap;
        VPort = &MyWindow->WScreen->ViewPort;

        if (!(pen_obtained))
        {
            WBColorTable[0] = 0x01000000;
            WBColorTable[3*256+1] = 0;
            GetRGB32(ColorMap,0,256,WBColorTable+1);
            for (i=0;i<(3*256+2);i++)
                ColorTable[i] = WBColorTable[i];
            for (i=0; i<256; i++)
            {
                    r = Table[3*i+1];
                    g = Table[3*i+2];
                    b = Table[3*i+3];
                    r=r&0xFF000000;
                    g=g&0xFF000000;
                    b=b&0xFF000000;
                    transtable[i] = ObtainBestPenA(ColorMap,r,g,b,EmptyTags);
            }
        }
        for (i=0; i<256; i++)
        {                
                ColorTable[3*transtable[i]+1] = Table[3*i+1];
                ColorTable[3*transtable[i]+2] = Table[3*i+2];
                ColorTable[3*transtable[i]+3] = Table[3*i+3];
        }
        LoadRGB32(VPort,ColorTable);
        pen_obtained = TRUE;
}
#endif

#ifdef STORM
void Initialize_Display_Process(char *name)
#else
void Initialize_Display_Process(name)
char *name;
#endif
{
    int crv, cbu, cgu, cgv;
    int Y, Cb, Cr, R, G, B;
    int i;
    unsigned char *temp;
    ULONG mycolors[770];

    displayIsOpen = TRUE;

    displayBitMap.Planes[0]=0;

    /* no mode selected, request one */

    if(Mode_ID == INVALID_ID)
    {
        struct ScreenModeRequester *sreq = NULL;
     if (!wb)
     {
#ifdef STORM
        if(sreq = (struct ScreenModeRequester *)AllocAslRequest(ASL_ScreenModeRequest,asltags))
#else
        if(sreq = (struct ScreenModeRequester *)AllocAslRequestTags(ASL_ScreenModeRequest,TAG_END))
#endif
        {
            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;
    }
#ifdef STORM
    if (!(ChunkyPPCBase = OpenLibrary("chunkyppc.library",0)))
    {
     direct=0;
    }
#endif
    IO_StartupTimer();
    /* setup automatically closing of the display */

#ifndef STORM
    if(onbreak(&__amiga_exit)) Error("onbreak failed");
#endif
    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 */

        if (!wb)
        {
         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 (!wb)
        {
         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");
        }
    }

#ifdef STORM
    if ((Coded_Picture_Width*Double_Pixels)%64==0) opt=0;
    else if ((Coded_Picture_Width*Double_Pixels)%8==0) opt=1;
    else opt=2;
#endif

    /* open window */

#ifdef STORM
        if (direct)
        {
         helpbuf[0].ti_Tag=LBMI_BASEADDRESS;
         helpbuf[0].ti_Data=(ULONG)&address;
         helpbuf[1].ti_Tag=LBMI_BYTESPERROW;
         helpbuf[1].ti_Data=(ULONG)&bpr;
         helpbuf[2].ti_Tag=TAG_END;
         helpbuf[2].ti_Data=0;
         UnLockBitMap(LockBitMapTagList((displayScreen->RastPort).BitMap,helpbuf));
        }
#endif

    if (wb)
    {
     direct=0;
     displayIsNative=0;
     if(!(displayWindow = OpenWindowTags(NULL,
                        WA_Title,"MPEG-2 Display",
                        WA_InnerWidth,Coded_Picture_Width*Double_Pixels,
                        WA_InnerHeight,Coded_Picture_Height*Double_Pixels,
                        WA_GimmeZeroZero,TRUE,
                        WA_DragBar,TRUE,
                        WA_DepthGadget,TRUE,
                        WA_IDCMP,IDCMP_RAWKEY,
                        WA_Activate,TRUE,
                        WA_NewLookMenus,TRUE,
                        TAG_END)))
        Error("OpenWindowTags failed");
     wbcolors=(UBYTE *)AllocVec(256*4,MEMF_FAST|MEMF_CLEAR);
     if (!wbcolors)
     {
      Error("Not enough memory");
     }
     colarray1=&(transtable[0]);
     WBColorTable[0] = 0x01000000;
     WBColorTable[3*256+1] = 0;
     GetRGB32((displayWindow->WScreen->ViewPort).ColorMap,0,256,WBColorTable+1);
    }
    else
    {

    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 */
    rp=displayWindow->RPort;
    SetAPen(rp,1);
    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 */
    mycolors[0]=0x01000000;
    mycolors[3*256+1]=0;
    mycolors[1]=255<<24;
    mycolors[2]=255<<24;
    mycolors[3]=255<<24;
    for (i=1;i<16;i++)
    {
     mycolors[3*i+1]=0;
     mycolors[3*i+2]=0;
     mycolors[3*i+3]=0;
    }
    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];
        mycolors[3*i+1]=R<<24;
        mycolors[3*i+2]=G<<24;
        mycolors[3*i+3]=B<<24;
        //if (!wb) SetRGB32(&displayScreen -> ViewPort,i,R<<24,G<<24,B<<24);
        Pixel[i] = i;
    }
    if (!wb) LoadRGB32(&displayScreen->ViewPort,mycolors);
    else LoadRGBRtg(displayWindow,mycolors);
    /* 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)*4*(Coded_Picture_Height))))
        Error("malloc failed");

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

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

extern int fpscount;

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

    if (!wb)
    {
     //for(i=0;i<256;i++) ReleasePen( (displayScreen -> ViewPort).ColorMap,Pixel[i]);
    }
    else
    {
     int i;
     struct ColorMap *ColorMap=((displayWindow->WScreen)->ViewPort).ColorMap;
     for (i=0; i<256; i++) ReleasePen(ColorMap,transtable[i]);
     LoadRGB32(&(displayWindow->WScreen->ViewPort),WBColorTable);
     FreeVec(wbcolors);
    }

    if(displayWindow) CloseWindow(displayWindow);
    if(displayScreen&&(!wb)) CloseScreen(displayScreen);

    if (!wb)
    {
     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;
    }
#ifdef STORM
    if (ChunkyPPCBase)
    {
        CloseLibrary(ChunkyPPCBase);
        ChunkyPPCBase=NULL;
    }
#endif
    IO_ShutdownTimer();
if (fpscount) printf("Average fps rate: %f\n",(float)(((float)frames)/((float)secs)));
}

int Frame_Count = NULL;
extern int fpscount;
int truecolor=1;

void ARGBtoBGR(unsigned char *address,unsigned char *Dithered_Image,int w,int h,int bpr);


UBYTE *taste=(UBYTE *)0xbfec01;

#ifdef STORM
void ConvertFrame(UBYTE *,UBYTE *,unsigned long);
static void Display_Image(void *Ximage_Ptr,unsigned char *Dithered_Image)
#else
static void Display_Image(Ximage_Ptr,Dithered_Image)
void *Ximage_Ptr;
unsigned char *Dithered_Image;
#endif
{
    //static int count=0;
    //printf("display: %ld\r",count++);
    //fflush(stdout);

    /* scale picture to the double if -h is present */
    if (*taste==0x39)
    {
     Terminate_Display_Process();
     exit(0);
    }

    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 (!wb)
    {
#ifdef STORM
    if (direct)
    {
      if (!displayIsNative)
      {
       if (opt==0) ChunkyNoffFastest(address,Dithered_Image,(Coded_Picture_Width*Double_Pixels),(Coded_Picture_Height*Double_Pixels),bpr);
       else if (opt==1) ChunkyNoffFast(address,Dithered_Image,(Coded_Picture_Width*Double_Pixels),(Coded_Picture_Height*Double_Pixels),bpr);
       else ChunkyNoffNormal(address,Dithered_Image,(Coded_Picture_Width*Double_Pixels),(Coded_Picture_Height*Double_Pixels),bpr);
      }
      else 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
#endif
    {
     if (!truecolor)
     {
     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);
     }
     else
     {
      WritePixelArray(Dithered_Image,0,0,4*Coded_Picture_Width*Double_Pixels,rp,0,0,Coded_Picture_Width*Double_Pixels,Coded_Picture_Height*Double_Pixels,RECTFMT_ARGB);
     }
    }
    }
    else
    {
     if (!truecolor)
     {
      ConvertFrame(Dithered_Image,transtable,Coded_Picture_Width*Double_Pixels*Coded_Picture_Height*Double_Pixels);
      WritePixelArray8(rp,0,0,(Coded_Picture_Width*Double_Pixels)-1,(Coded_Picture_Height*Double_Pixels)-1,Dithered_Image,rp);
     }
     else
     {
      WritePixelArray(Dithered_Image,0,0,4*Coded_Picture_Width*Double_Pixels,rp,0,0,Coded_Picture_Width*Double_Pixels,Coded_Picture_Height*Double_Pixels,RECTFMT_ARGB);
     }
    }
    if (fpscount) video_do_fps();
}

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;
  }
}

static void conv422to444(unsigned char *src,unsigned char *dst)
{
  int i, i2, w, j, im3, im2, im1, ip1, ip2, ip3;

  w = Coded_Picture_Width>>1;

  if (base.MPEG2_Flag)
  {
    for (j=0; j<Coded_Picture_Height; j++)
    {
      for (i=0; i<w; i++)
      {
        i2 = i<<1;
        im2 = (i<2) ? 0 : i-2;
        im1 = (i<1) ? 0 : i-1;
        ip1 = (i<w-1) ? i+1 : w-1;
        ip2 = (i<w-2) ? i+2 : w-1;
        ip3 = (i<w-3) ? i+3 : w-1;

        /* FIR filter coefficients (*256): 21 0 -52 0 159 256 159 0 -52 0 21 */
        /* even samples (0 0 256 0 0) */
        dst[i2] = src[i];

        /* odd samples (21 -52 159 159 -52 21) */
        dst[i2+1] = Clip[(int)(21*(src[im2]+src[ip3])
                        -52*(src[im1]+src[ip2])
                       +159*(src[i]+src[ip1])+128)>>8];
      }
      src+= w;
      dst+= Coded_Picture_Width;
    }
  }
  else
  {
    for (j=0; j<Coded_Picture_Height; j++)
    {
      for (i=0; i<w; i++)
      {

        i2 = i<<1;
        im3 = (i<3) ? 0 : i-3;
        im2 = (i<2) ? 0 : i-2;
        im1 = (i<1) ? 0 : i-1;
        ip1 = (i<w-1) ? i+1 : w-1;
        ip2 = (i<w-2) ? i+2 : w-1;
        ip3 = (i<w-3) ? i+3 : w-1;

        /* FIR filter coefficients (*256): 5 -21 70 228 -37 11 */
        dst[i2] =   Clip[(int)(  5*src[im3]
                         -21*src[im2]
                         +70*src[im1]
                        +228*src[i]
                         -37*src[ip1]
                         +11*src[ip2]+128)>>8];

       dst[i2+1] = Clip[(int)(  5*src[ip3]
                         -21*src[ip2]
                         +70*src[ip1]
                        +228*src[i]
                         -37*src[im1]
                         +11*src[im2]+128)>>8];
      }
      src+= w;
      dst+= Coded_Picture_Width;
    }
  }
}

/* vertical 1:2 interpolation filter */
static void conv420to422(unsigned char *src,unsigned char *dst)
{
  int w, h, i, j, j2;
  int jm6, jm5, jm4, jm3, jm2, jm1, jp1, jp2, jp3, jp4, jp5, jp6, jp7;

  w = Coded_Picture_Width>>1;
  h = Coded_Picture_Height>>1;

  if (progressive_frame)
  {
    /* intra frame */
    for (i=0; i<w; i++)
    {
      for (j=0; j<h; j++)
      {
        j2 = j<<1;
        jm3 = (j<3) ? 0 : j-3;
        jm2 = (j<2) ? 0 : j-2;
        jm1 = (j<1) ? 0 : j-1;
        jp1 = (j<h-1) ? j+1 : h-1;
        jp2 = (j<h-2) ? j+2 : h-1;
        jp3 = (j<h-3) ? j+3 : h-1;

        /* FIR filter coefficients (*256): 5 -21 70 228 -37 11 */
        /* New FIR filter coefficients (*256): 3 -16 67 227 -32 7 */
        dst[w*j2] =     Clip[(int)(  3*src[w*jm3]
                             -16*src[w*jm2]
                             +67*src[w*jm1]
                            +227*src[w*j]
                             -32*src[w*jp1]
                             +7*src[w*jp2]+128)>>8];

        dst[w*(j2+1)] = Clip[(int)(  3*src[w*jp3]
                             -16*src[w*jp2]
                             +67*src[w*jp1]
                            +227*src[w*j]
                             -32*src[w*jm1]
                             +7*src[w*jm2]+128)>>8];
      }
      src++;
      dst++;
    }
  }
  else
  {
    /* intra field */
    for (i=0; i<w; i++)
    {
      for (j=0; j<h; j+=2)
      {
        j2 = j<<1;

        /* top field */
        jm6 = (j<6) ? 0 : j-6;
        jm4 = (j<4) ? 0 : j-4;
        jm2 = (j<2) ? 0 : j-2;
        jp2 = (j<h-2) ? j+2 : h-2;
        jp4 = (j<h-4) ? j+4 : h-2;
        jp6 = (j<h-6) ? j+6 : h-2;

        /* Polyphase FIR filter coefficients (*256): 2 -10 35 242 -18 5 */
        /* New polyphase FIR filter coefficients (*256): 1 -7 30 248 -21 5 */
        dst[w*j2] = Clip[(int)(  1*src[w*jm6]
                         -7*src[w*jm4]
                         +30*src[w*jm2]
                        +248*src[w*j]
                         -21*src[w*jp2]
                          +5*src[w*jp4]+128)>>8];

        /* Polyphase FIR filter coefficients (*256): 11 -38 192 113 -30 8 */
        /* New polyphase FIR filter coefficients (*256):7 -35 194 110 -24 4 */
        dst[w*(j2+2)] = Clip[(int)( 7*src[w*jm4]
                             -35*src[w*jm2]
                            +194*src[w*j]
                            +110*src[w*jp2]
                             -24*src[w*jp4]
                              +4*src[w*jp6]+128)>>8];

        /* bottom field */
        jm5 = (j<5) ? 1 : j-5;
        jm3 = (j<3) ? 1 : j-3;
        jm1 = (j<1) ? 1 : j-1;
        jp1 = (j<h-1) ? j+1 : h-1;
        jp3 = (j<h-3) ? j+3 : h-1;
        jp5 = (j<h-5) ? j+5 : h-1;
        jp7 = (j<h-7) ? j+7 : h-1;

        /* Polyphase FIR filter coefficients (*256): 11 -38 192 113 -30 8 */
        /* New polyphase FIR filter coefficients (*256):7 -35 194 110 -24 4 */
        dst[w*(j2+1)] = Clip[(int)( 7*src[w*jp5]
                             -35*src[w*jp3]
                            +194*src[w*jp1]
                            +110*src[w*jm1]
                             -24*src[w*jm3]
                              +4*src[w*jm5]+128)>>8];

        dst[w*(j2+3)] = Clip[(int)(  1*src[w*jp7]
                             -7*src[w*jp5]
                             +30*src[w*jp3]
                            +248*src[w*jp1]
                             -21*src[w*jm1]
                              +5*src[w*jm3]+128)>>8];
      }
      src++;
      dst++;
    }
  }
}

/* Convert YUV->RGB *without* using interpolation */
static void yuv_to_rgb_noint(unsigned char *src[],unsigned char *dst)
{
  int i,j;
  int y,u,v;
  int crv, cbu, cgu, cgv;
  unsigned char *py,*pu,*pv;
  unsigned char r, g, b, xdiffy, xdiffuv;

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

  /* 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];

  xdiffuv = xdiffy = Coded_Picture_Width-horizontal_size;
  if (chroma_format!=CHROMA444)
    xdiffuv/=2;

  for (j=0; j<vertical_size; j++)
  {
    for (i=0; i<horizontal_size; i++)
    {
      if (i%2==0)
      {
        u = *pu++ - 128;
        v = *pv++ - 128;
      }
      else if (chroma_format==CHROMA444)
      {
        u = *pu++ - 128;
        v = *pv++ - 128;
      }

      y = 76309 * (*py++ - 16); /* (255/219)*65536 */

      r = Clip[(y + crv*v + 32768)>>16];
      g = Clip[(y - cgu*u - cgv*v + 32768)>>16];
      b = Clip[(y + cbu*u + 32786)>>16];

      *dst++ = r;
      *dst++ = g;
      *dst++ = b;
      *dst++ = b;
    }

    /* Increase pointers */
    py+=xdiffy;
    pu+=xdiffuv;
    pv+=xdiffuv;

    if (chroma_format==CHROMA420 && j%2==0)
    {
      pu -= Chroma_Width;
      pv -= Chroma_Width;
    }
  }
}

/* Convert YUV->RGB using interpolation */
static void yuv_to_rgb_int(unsigned char *src[],unsigned char *dst)
{
  int i, j;
  int y, u, v;
  int crv, cbu, cgu, cgv;
  int height, incr;
  unsigned char *py, *pu, *pv;
  unsigned char r, g, b;
  static unsigned char *u422, *v422, *u444, *v444;

  /* Init */
  height=vertical_size;
  incr=Coded_Picture_Width;

  /* Perform conversion */

  if (chroma_format==CHROMA444)
  {
    u444 = src[1];
    v444 = src[2];
  }
  else
  {
    if (!u444)
    {
      if (chroma_format==CHROMA420)
      {
        if (!(u422 = (unsigned char *)malloc((Coded_Picture_Width>>1)
                                             *Coded_Picture_Height)))
          Error("malloc failed");
        if (!(v422 = (unsigned char *)malloc((Coded_Picture_Width>>1)
                                             *Coded_Picture_Height)))
          Error("malloc failed");
      }

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

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

    if (chroma_format==CHROMA420)
    {
      conv420to422(src[1],u422);
      conv420to422(src[2],v422);
      conv422to444(u422,u444);
      conv422to444(v422,v444);
    }
    else
    {
      conv422to444(src[1],u444);
      conv422to444(src[2],v444);
    }
  }

  /* 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];

  for (i=0; i<height; i++)
  {
    py = src[0] + incr*i;
    pu = u444 + incr*i;
    pv = v444 + incr*i;

    for (j=0; j<horizontal_size; j++)
    {
      u = *pu++ - 128;
      v = *pv++ - 128;
      y = 76309 * (*py++ - 16); /* (255/219)*65536 */
      r = Clip[(y + crv*v + 32768)>>16];
      g = Clip[(y - cgu*u - cgv*v + 32768)>>16];
      b = Clip[(y + cbu*u + 32786)>>16];

      *dst++ = r;
      *dst++ = g;
      *dst++ = b;
      *dst++ = b;
    }
  }
}

static void yuv_to_rgb(unsigned char *src[],unsigned char *dst)
{
#ifdef BLA
    yuv_to_rgb_int(src,dst);
#else
    yuv_to_rgb_noint(src,dst);
#endif
}

static void Dither_Frame_TrueCol(unsigned char *src[])
{
  if (!displayIsNative)
  {
    /* Perform YUV->RGB directly to destination */
    yuv_to_rgb(src, Dithered_Image);
  }
  else
  {
    /* YUV->RGB */
    //yuv_to_rgb(src, RGB_Image);

    /* RGB -> HAM6/8 conversion */
    //ham_c2p(RGB_Image, Dithered_Image, horizontal_size, vertical_size);
    // Fix this still...
  }
}

#ifdef STORM
void dither(unsigned char *src[])
#else
void dither(src)
unsigned char *src[];
#endif
{
  /* 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 (truecolor==0)
  {
  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);
      }
    }
  }
  }
  else
  {
   Dither_Frame_TrueCol(src);
  }

  Display_Image(Ximage_Ptr,Dithered_Image);
}

#ifdef STORM
static void Dither_Frame(unsigned char *src[])
#else
static void Dither_Frame(src)
unsigned char *src[];
#endif
{
  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]];
    }
  }

}

#ifdef STORM
static void Dither_Top_Field(unsigned char *src[], unsigned char *dst)
#else
static void Dither_Top_Field(src,dst)
unsigned char *src[];
unsigned char *dst;
#endif
{
  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;
  }
}

#ifdef STORM
static void Dither_Bottom_Field(unsigned char *src[], unsigned char *dst)
#else
static void Dither_Bottom_Field(src,dst)
unsigned char *src[];
unsigned char *dst;
#endif
{
  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;
  }
}

#ifndef STORM
static void Dither_Top_Field420(src,dst)
unsigned char *src[];
unsigned char *dst;
#else
static void Dither_Top_Field420(unsigned char *src[],unsigned char *dst)
#endif
{
  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;
  }
}

#ifdef STORM
static void Dither_Bottom_Field420(unsigned char *src[],unsigned char *dst)
#else
static void Dither_Bottom_Field420(src,dst)
unsigned char *src[];
unsigned char *dst;
#endif
{
  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
