
/*
 *   MediaMVP Server Library
 *
 *   (C) 2004 Dominic Morris
 *
 *   $Id: render.c,v 1.4 2004/05/27 19:08:10 dom Exp $
 *   $Date: 2004/05/27 19:08:10 $
 *
 *
 *   Handle rendering onto the RGB buffer stuff we've got
 *
 *   And yup, some form of OO would be kinda handy here <grin>
 */

#include "mvprender.h"

#include "default_font.h"


#define OFFSET_Y          32
#define OFFSET_X          32

#if 0
#define DEBUG(xxx...) fprintf(stderr,xxx)
#else
#define DEBUG(xxx,...)
#endif


struct _render {
    surface_t  *surface;
    int         width;
    int         depth;
    uint32_t    fgcol;
    uint32_t    bgcol;
    font_t	*font;
};


static void     render_print(render_t *render, int x, int y, int maxx,  char *text);
static void     printchar(render_t *render,int x, int y, glyph_t *glyph);

extern glyph_t nbsp;

render_t *new_render(int width, int depth)
{
    render_t  *render = (render_t*)malloc(sizeof(*render));

    if ( render == NULL ) {
        return NULL;
    }

    /* Set up sizes */
    render->width = width;
    render->depth  = depth;
    render->surface = surface_alloc(width,depth,8);
    render->fgcol = 0x00FFFFFF;
    render->bgcol = 0x00000000;


    /* Setup a default font so we can at least display something.. */
    render->font = font_read(default_font);

    /* Set up some handy functions.. */
    return render;
}


void delete_render(render_t *render)
{
    if ( render == NULL ) {
        return;
    }

    if(render->font) {
        delete_font(render->font);
    }

    surface_dealloc(render->surface);

    free(render);
}

void render_clear(render_t *render)
{
    surface_clear(render->surface,render->bgcol);
}

void *render_rgb2yvuy(render_t *render, int *size)
{
    if ( !surface_get_dirty(render->surface) ) {
        return NULL;
    }

    surface_set_dirty(render->surface,FALSE);

    return surface_map(render->surface,MAP_YVU,size);
}

void render_set_font(render_t *render, font_t *font)
{
    if ( render->font ) {
        delete_font(render->font);
    }

    render->font = font;
}

font_t *render_get_font(render_t *render)
{
    return render->font;
}

font_t *render_swap_font(render_t *render, font_t *font)
{
    font_t    *old = render->font;

    render->font = font;

    return old;
}


void render_set_fgcol(render_t *render, uint32_t rgb)
{
    render->fgcol = rgb;
}

void render_set_bgcol(render_t *render, uint32_t rgb)
{
    render->bgcol = rgb;
}

void render_printrow(render_t *render, int row,  char *text)
{
    int  x,y;

    x = OFFSET_X;
    y = row * font_get_height(render->font) + OFFSET_Y;

    render_print(render,x,y,render->width - OFFSET_X,text);
}

void render_printrow_width(render_t *render, int row, int x, int width, char *text)
{
    int      y;

    y = row * font_get_height(render->font) + OFFSET_Y;

    x += OFFSET_X;

    width += x;

    render_print(render,x,y,width,text);
}


void render_print(render_t *render, int x, int y, int maxwidth, char *text)
{
    glyph_t  *glyph;
    int   tabwidth = ( (maxwidth - x )  ) / 6;
    int width  = 0;

    /* Check to see if a font is defined */
    if(! render->font) {
        Dprintf(ERROR, "No font defined for render\n");
        return;
    }

    while ( *text ) {
        switch ( *text ) {
        case '\t':        /* Do some nasty stuff to calculate tab stops,
                             only really works for a full display */
            DEBUG( "render_print(tabstop)\n");
            glyph_set_height(&nbsp, font_get_height(render->font));
            while ( x + 1 < ( ( x / tabwidth ) + 1 ) * tabwidth && x < maxwidth ) {
                printchar(render,x,y, &nbsp);
                x++;
            }
            break;
        case '\n':
            DEBUG( "render_print(cr)\n");
            glyph_set_height(&nbsp, font_get_height(render->font));
            width = glyph_get_width(&nbsp);
            while ( x + width < maxwidth ) {
                printchar(render,x,y,&nbsp);
                x += width;
            }
            y += font_get_height(render->font);
            if ( y >= render->depth - OFFSET_Y ) {
                return;
            }
            break;
        default:
            DEBUG( "render_print(%c)\n", *(unsigned char *)text);
            if(font_is_defined(render->font, *(unsigned char *)text)) {
                glyph = font_get_glyph(render->font, *(unsigned char *)text);
                width = glyph_get_width(glyph);
                if ( x + width < maxwidth &&
                     ( y < render->depth - OFFSET_Y) ) {
                    printchar(render,x,y,glyph);
                    x += width;
                }
            }
            break;
        }
        text++;
    }
}

static void printchar(render_t *render,int x, int y, glyph_t *glyph)
{
    int *bitmap;
    int i,j, mask;
    int width, height;


    bitmap = glyph_get_bitmap(glyph);

    width = glyph_get_width(glyph);
    height = glyph_get_height(glyph);

    for(j = 0 ; j < height; j++) {
        for ( i = 0; i < width; i++ ) {
            mask = 1 << i;
            if ( bitmap && (bitmap[j] & mask ) ) {
                surface_set_pixel(render->surface,x + (width - i),y,render->fgcol);
            } else {
                surface_set_pixel(render->surface,x + (width - i),y,render->bgcol);
            }
        }
        y++;
    }
}


int render_get_maxrows(render_t *render)
{
    return ((render->depth - ( OFFSET_Y * 2) ) / font_get_height(render->font));
}

int render_get_depth(render_t *render)
{
    return render->depth;
}

int render_get_width(render_t *render)
{
    return render->width;
}

/* Ugly hack by Dave Kelly */
int render_get_font_width(render_t *render)
{
    return font_get_width(render->font);
}

int render_get_font_height(render_t *render)
{
    return font_get_height(render->font);
}

int render_get_textspace(render_t *render,  char *text)
{
    glyph_t  *glyph;
    int   width = 0;

    while ( *text ) {
	if(font_is_defined(render->font, *(unsigned char *)text)) {
	    glyph = font_get_glyph(render->font, *(unsigned char *)text);
            width += glyph_get_width(glyph);
        }
        text++;
    }

    return width;
}

int render_get_xoffset(render_t *render)
{
    return OFFSET_X;
}

int render_get_yoffset(render_t *render)
{
    return OFFSET_Y;
}

void render_mark_dirty(render_t *render)
{
    surface_set_dirty(render->surface,TRUE);
}

surface_t *render_attach_surface(render_t *render,surface_t *sfc)
{
    surface_t *old = render->surface;

    render->surface = sfc;
    surface_set_dirty(render->surface,TRUE);

    return old;
}


/*
 * Local Variables:
 *  indent-tabs-mode:nil
 *  require-final-newline:t
 *  c-basic-offset: 4
 * End:
 */
