/*
 *  Generic low-level drawing operations for a cfb frame buffer
 *
 *  (C) Copyright 2002 Geert Uytterhoeven
 *
 *  This file is subject to the terms and conditions of the GNU General Public
 *  License. See the file COPYING in the main directory of this archive for
 *  more details.
 */

#include "types.h"
#include "drawops.h"
#include "bitstream.h"
#include "fb.h"


#define EXP1(x)		0xffffffffU*x
#define EXP2(x)		0x55555555U*x
#define EXP4(x)		0x11111111U*0x ## x

static const u32 bpp1tab[2] = {
    EXP1(0), EXP1(1)
};

static const u32 bpp2tab[4] = {
    EXP2(0), EXP2(1), EXP2(2), EXP2(3)
};

static const u32 bpp4tab[16] = {
    EXP4(0), EXP4(1), EXP4(2), EXP4(3), EXP4(4), EXP4(5), EXP4(6), EXP4(7),
    EXP4(8), EXP4(9), EXP4(a), EXP4(b), EXP4(c), EXP4(d), EXP4(e), EXP4(f)
};


static u32 next_line;

int cfb_init(void)
{
    if (fb_fix.type != FB_TYPE_PACKED_PIXELS || fb_var.bits_per_pixel > 32)
	return 0;

    next_line =
	fb_fix.line_length ? fb_fix.line_length
			   : fb_var.xres_virtual*fb_var.bits_per_pixel/8;
    return 1;
}


    /*
     *  Expand a pixel value to a 32-bit pattern
     */

static inline u32 pixel_to_pat32(pixel_t pixel)
{
    u32 pat = pixel;

    switch (fb_var.bits_per_pixel) {
	case 1:
	    pat = bpp1tab[pat];
	    break;

	case 2:
	    pat = bpp2tab[pat];
	    break;

	case 4:
	    pat = bpp4tab[pat];
	    break;

	case 8:
	    pat |= pat << 8;
	    // Fall through
	case 16:
	    pat |= pat << 16;
	    // Fall through
	case 32:
	    break;
    }
    return pat;
}


    /*
     *  Expand a pixel value to a generic 32/64-bit pattern and rotate it to
     *  the correct start position
     */

static inline unsigned long pixel_to_pat(pixel_t pixel, int left)
{
    unsigned long pat = pixel;
    u32 bpp = fb_var.bits_per_pixel;
    int i;

    /* expand pixel value */
    for (i = bpp; i < BITS_PER_LONG; i *= 2)
	pat |= pat << i;

    /* rotate pattern to correct start position */
    pat = pat << left | pat >> (bpp-left);
    return pat;
}


void cfb_draw_hline(u32 x, u32 y, u32 length, pixel_t pixel)
{
    unsigned long *dst;
    int dst_idx, left;
    u32 bpp = fb_var.bits_per_pixel;

    dst = (unsigned long *)((unsigned long)fb & ~(BYTES_PER_LONG-1));
    dst_idx = ((unsigned long)fb & (BYTES_PER_LONG-1))*8;
    dst_idx += y*next_line*8+x*bpp;
    dst += dst_idx >> SHIFT_PER_LONG;
    dst_idx &= (BITS_PER_LONG-1);
    /* FIXME For now we support 1-32 bpp only */
    left = BITS_PER_LONG % bpp;
    if (!left) {
	u32 pat = pixel_to_pat32(pixel);
	bitfill32(dst, dst_idx, pat, length*bpp);
    } else {
	unsigned long pat = pixel_to_pat(pixel, (left-dst_idx) % bpp);
	bitfill(dst, dst_idx, pat, left, bpp-left, length*bpp);
    }
}

void cfb_fill_rect(u32 x, u32 y, u32 width, u32 height, pixel_t pixel)
{
    unsigned long *dst;
    int dst_idx, left;
    u32 bpp = fb_var.bits_per_pixel;

    dst = (unsigned long *)((unsigned long)fb & ~(BYTES_PER_LONG-1));
    dst_idx = ((unsigned long)fb & (BYTES_PER_LONG-1))*8;
    dst_idx += y*next_line*8+x*bpp;
    /* FIXME For now we support 1-32 bpp only */
    left = BITS_PER_LONG % bpp;
    if (!left) {
	u32 pat = pixel_to_pat32(pixel);
	while (height--) {
	    dst += dst_idx >> SHIFT_PER_LONG;
	    dst_idx &= (BITS_PER_LONG-1);
	    bitfill32(dst, dst_idx, pat, width*bpp);
	    dst_idx += next_line*8;
	}
    } else {
	unsigned long pat = pixel_to_pat(pixel, (left-dst_idx) % bpp);
	int right = bpp-left;
	int r;
	while (height--) {
	    dst += dst_idx >> SHIFT_PER_LONG;
	    dst_idx &= (BITS_PER_LONG-1);
	    bitfill(dst, dst_idx, pat, left, right, width*bpp);
	    r = (next_line*8) % bpp;
	    pat = pat << (bpp-r) | pat >> r;
	    dst_idx += next_line*8;
	}
    }
}

void cfb_copy_rect(u32 dx, u32 dy, u32 width, u32 height, u32 sx, u32 sy)
{
    unsigned long *dst, *src;
    int dst_idx, src_idx;
    u32 bpp = fb_var.bits_per_pixel;
    int rev_copy = 0;

    if (dy > sy || (dy == sy && dx > sx)) {
	dy += height;
	sy += height;
	rev_copy = 1;
    }
    dst = src = (unsigned long *)((unsigned long)fb & ~(BYTES_PER_LONG-1));
    dst_idx = src_idx = ((unsigned long)fb & (BYTES_PER_LONG-1))*8;
    dst_idx += dy*next_line*8+dx*bpp;
    src_idx += sy*next_line*8+sx*bpp;
    if (rev_copy) {
	while (height--) {
	    dst_idx -= next_line*8;
	    src_idx -= next_line*8;
	    dst += dst_idx >> SHIFT_PER_LONG;
	    dst_idx &= (BITS_PER_LONG-1);
	    src += src_idx >> SHIFT_PER_LONG;
	    src_idx &= (BITS_PER_LONG-1);
	    bitcpy_rev(dst, dst_idx, src, src_idx, width*bpp);
	}
    } else {
	while (height--) {
	    dst += dst_idx >> SHIFT_PER_LONG;
	    dst_idx &= (BITS_PER_LONG-1);
	    src += src_idx >> SHIFT_PER_LONG;
	    src_idx &= (BITS_PER_LONG-1);
	    bitcpy(dst, dst_idx, src, src_idx, width*bpp);
	    dst_idx += next_line*8;
	    src_idx += next_line*8;
	}
    }
}

