/*
 * yuv422_8bpp.c
 * Copyright (C) 2002 P.Everett <peter@everett9981.freeserve.co.uk>
 *
 * This file is part of KinoAMP, a free RISCOS MPEG program stream decoder.
 *
 * KinoAMP is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * KinoAMP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*
 * This file contains the YUV422 output functions for 8bpp modes.
 */

#include <string.h>
#include "inttypes.h"
#include "ka_drawers.h"

/**
 * Converts an YUV422 source into a destination with 256 colours, 400% zoom.
 *
 * @param  paint  draw parameters
 */
void ka_drawyuv422_z4_8bpp(const ka_paint_t* paint)
{
  int height;
  uint32_t *dst1, *dst2, *dst3, *dst4;
  uint8_t *y1;
  uint8_t *u, *v;
  int dst_skip;
  int i;
  uint32_t *ct = (uint32_t*) ka_yuv_colour_table;


  height = paint->yc_height;
  dst1 = (uint32_t*) paint->dst;               // 1 row screen address
  dst2 = dst1 + paint->dst_bpr/4;              // 2 row screen address
  dst3 = dst2 + paint->dst_bpr/4;              // 3 row screen address
  dst4 = dst3 + paint->dst_bpr/4;              // 4 row screen address

  y1 = (uint8_t*) paint->base.y;               // row luminance address

  u = (uint8_t*) paint->base.cr;               // chroma r source address
  v = (uint8_t*) paint->base.cb;               // chroma b source address

  dst_skip = (3*paint->dst_bpr + paint->dst_skip) >> 2;

  do
  {
    i = (paint->yc_width >> 1);
    do
    {
      uint32_t uv, yuv, row1, row2;

      uv = (*v++)>>4;
      uv |= (*u++) & 0xf0;
      uv <<= 5;

      // W
      yuv = uv | (((*y1++) & 0xf8)>>3);
      row1 = ct[yuv];
      // E
      yuv = uv | (((*y1++) & 0xf8)>>3);
      row2 = ct[yuv];

      *dst1++ = row1;
      *dst1++ = row2;
      row1 = (row1<<16) | (row1>>16);
      *dst2++ = row1;
      row2 = (row2<<24) | (row2>>8);
      *dst2++ = row2;
      row1 = (row1<<24) | (row1>>8);
      *dst3++ = row1;
      row2 = (row2<<16) | (row2>>16);
      *dst3++ = row2;
      row1 = (row1<<16) | (row1>>16);
      *dst4++ = row1;
      row2 = (row2<<24) | (row2>>8);
      *dst4++ = row2;
    }
    while(--i);

    u += paint->uv_skip;
    v += paint->uv_skip;
    y1 += paint->yc_skip;
    dst1 += dst_skip;
    dst2 += dst_skip;
    dst3 += dst_skip;
    dst4 += dst_skip;
  }
  while(--height);
}

/**
 * Converts an YUV422 source into a destination with 256 colours, 300% zoom.
 *
 * @param  paint  draw parameters
 */
void ka_drawyuv422_z3_8bpp(const ka_paint_t* paint)
{
  int height;
  uint32_t *dst1, *dst2, *dst3;
  uint8_t *y1;
  uint8_t *u, *v;
  int dst_skip;
  int i;
  uint32_t *ct = (uint32_t*) ka_yuv_colour_table;


  height = paint->yc_height;
  dst1 = (uint32_t*) paint->dst;               // 1 row screen address
  dst2 = dst1 + paint->dst_bpr/4;              // 2 row screen address
  dst3 = dst2 + paint->dst_bpr/4;              // 3 row screen address

  y1 = (uint8_t*) paint->base.y;               // even row luminance address

  u = (uint8_t*) paint->base.cr;               // chroma r source address
  v = (uint8_t*) paint->base.cb;               // chroma b source address

  dst_skip = (2*paint->dst_bpr + paint->dst_skip) >> 2;

  do
  {
    i = paint->yc_width >> 2;
    do
    {
      uint32_t uv1, uv2, yuv, row1, row2, c;

      // first block of 2
      uv1 = (*v++)>>4;
      uv1 |= (*u++) & 0xf0;
      uv1 <<= 5;

      // second block of 2
      uv2 = (*v++)>>4;
      uv2 |= (*u++) & 0xf0;
      uv2 <<= 5;

      // W1
      yuv = uv1 | (((*y1++) & 0xf8)>>3);
      c = ct[yuv];
      row1 = ((c<<16)>>16) | ((c<<24)>>8);
      row2 = (c>>16) | (c & (255<<16));
      // E1
      yuv = uv1 | (((*y1++) & 0xf8)>>3);
      c = ct[yuv];
      row1 |= (c>>8)<<24;
      row2 |= c & 0xff000000;

      *dst3++ = *dst1++ = row1;
      *dst2++ = row2;

      row1 = (c<<16)>>16;
      row2 = c>>16;
      // W2
      yuv = uv2 | (((*y1++) & 0xf8)>>3);
      c = ct[yuv];
      row1 |= c<<16;
      row2 |= (c>>16)<<16;

      *dst3++ = *dst1++ = row1;
      *dst2++ = row2;

      row1 = c & 255;
      row2 = (c<<8)>>24;
      // E2
      yuv = uv2 | (((*y1++) & 0xf8)>>3);
      c = ct[yuv];
      row1 |= (c & (255<<8)) | (c<<16);
      row2 |= ((c>>24)<<8) | ((c>>16)<<16);

      *dst3++ = *dst1++ = row1;
      *dst2++ = row2;
    }
    while(--i);

    u += paint->uv_skip;
    v += paint->uv_skip;
    y1 += paint->yc_skip;
    dst1 += dst_skip;
    dst2 += dst_skip;
    dst3 += dst_skip;
  }
  while(--height);
}

/**
 * Converts an YUV422 source into a destination with 256 colours, 200% zoom.
 *
 * @param  paint  draw parameters
 */
void ka_drawyuv422_z2_8bpp(const ka_paint_t* paint)
{
  int height;
  uint32_t *dst1, *dst2;
  uint8_t *y1;
  uint8_t *u, *v;
  int dst_skip;
  int i;
  uint32_t *ct = (uint32_t*) ka_yuv_colour_table;


  height = paint->yc_height;
  dst1 = (uint32_t*) paint->dst;               // 1 row screen address
  dst2 = dst1 + paint->dst_bpr/4;              // 2 row screen address

  y1 = (uint8_t*) paint->base.y;               // even row luminance address

  u = (uint8_t*) paint->base.cr;               // chroma r source address
  v = (uint8_t*) paint->base.cb;               // chroma b source address

  dst_skip = (paint->dst_bpr + paint->dst_skip) >> 2;

  do
  {
    i = (paint->yc_width >> 1);
    do
    {
      uint32_t uv, yuv, row1, row2, c;

      uv = (*v++)>>4;
      uv |= (*u++) & 0xf0;
      uv <<= 5;

      // W
      yuv = uv | (((*y1++) & 0xf8)>>3);
      c = ct[yuv];
      row1 = (c<<16)>>16;
      row2 = c>>16;
      // E
      yuv = uv | (((*y1++) & 0xf8)>>3);
      c = ct[yuv];

      *dst1++ = row1 | (c<<16);
      *dst2++ = row2 | ((c>>16)<<16);
    }
    while(--i);

    u += paint->uv_skip;
    v += paint->uv_skip;
    y1 += paint->yc_skip;
    dst1 += dst_skip;
    dst2 += dst_skip;
  }
  while(--height);
}

/**
 * Converts an YUV422 source into a destination with 256 colours, 100% zoom.
 *
 * @param  paint  draw parameters
 */
void ka_drawyuv422_z1_8bpp(const ka_paint_t* paint)
{
  int height;
  uint32_t *dst;
  uint32_t *y;
  uint8_t *u, *v;
  int dst_skip, yc_skip;
  int i;


  height = paint->yc_height;
  dst = (uint32_t*) paint->dst;               // screen address

  y = (uint32_t*) paint->base.y;              // luminance address

  u = (uint8_t*) paint->base.cr;              // chroma r source address
  v = (uint8_t*) paint->base.cb;              // chroma b source address

  dst_skip = paint->dst_skip >> 2;
  yc_skip = paint->yc_skip >> 2;

  do
  {
    int j = height & 1;
    i = paint->yc_width >> 2;
    do
    {
      register uint32_t uv, yuv, yyyy_1, row1;

      // Chroma for the first block of 2 pixels
      uv = (*v++)>>4;
      uv |= (*u++) & 0xf0;
      uv = uv<<7;

      yyyy_1 = *y++;
      // W1
      yuv = ((yyyy_1>>1) & 0x7c) | uv;
      row1 = ka_yuv_colour_table[yuv+0+j];
      // E1
      yuv = ((yyyy_1>>9) & 0x7c) | uv;
      row1 |= ka_yuv_colour_table[yuv+1-j]<<8;

      // Chroma for the second block of 2 pixels
      uv = (*v++)>>4;
      uv |= (*u++) & 0xf0;
      uv = uv<<7;

      // W2
      yuv = ((yyyy_1>>17) & 0x7c) | uv;
      row1 |= ka_yuv_colour_table[yuv+0+j]<<16;
      // E2
      yuv = ((yyyy_1>>25) & 0x7c) | uv;
      row1 |= ka_yuv_colour_table[yuv+1-j]<<24;

      *dst++ = row1;
    }
    while(--i);

    u += paint->uv_skip;
    v += paint->uv_skip;
    y += yc_skip;
    dst += dst_skip;
  }
  while(--height);
}

/**
 * Converts an YUV422 source into a destination with 256 colours, 50% zoom.
 *
 * @param  paint  draw parameters
 */
void ka_drawyuv422_z05_8bpp(const ka_paint_t* paint)
{
  int height;
  uint32_t *dst;
  uint32_t *y;
  uint8_t *u, *v;
  int dst_skip, yc_skip, uv_skip;
  int i;


  height = paint->yc_height >> 1;
  dst = (uint32_t*) paint->dst;        // row screen address

  y = (uint32_t*) paint->base.y;       // first row luminance address

  u = (uint8_t*) paint->base.cr;       // first row chroma r source address
  v = (uint8_t*) paint->base.cb;       // first row chroma b source address

  dst_skip = paint->dst_skip >> 2;
  yc_skip = (paint->yc_bpr + paint->yc_skip) >> 2;
  uv_skip = paint->uv_skip + (paint->yc_bpr >> 1);

  do
  {
    int j = height & 1;
    i = paint->yc_width >> 3;
    do
    {
      register uint32_t uv, yuv, yyyy, row;

      // W1
      uv = (*v++)>>4;
      uv |= (*u++) & 0xf0;
      uv = uv<<7;
      yyyy = *y++;
      yuv = ((yyyy>>1) & 0x7c) | uv;
      row = ka_yuv_colour_table[yuv+0+j];

      // W2
      uv = (*v++)>>4;
      uv |= (*u++) & 0xf0;
      uv = uv<<7;
      yuv = ((yyyy>>17) & 0x7c) | uv;
      row |= ka_yuv_colour_table[yuv+1-j]<<8;

      // W3
      uv = (*v++)>>4;
      uv |= (*u++) & 0xf0;
      uv = uv<<7;
      yyyy = *y++;
      yuv = ((yyyy>>1) & 0x7c) | uv;
      row |= ka_yuv_colour_table[yuv+0+j]<<16;

      // W4
      uv = (*v++)>>4;
      uv |= (*u++) & 0xf0;
      uv = uv<<7;
      yuv = ((yyyy>>17) & 0x7c) | uv;
      row |= ka_yuv_colour_table[yuv+1-j]<<24;

      *dst++ = row;
    }
    while(--i);

    u += uv_skip;
    v += uv_skip;
    y += yc_skip;
    dst += dst_skip;
  }
  while(--height);
}
