
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cgm_soft.h"

#ifdef PSP

#define XS 480
#define YS 272

#else

#define XS 320
#define YS 200

#endif

void cgm_tri(unsigned char *s,int *v,unsigned char col);
void cgm_line(unsigned char *s,int *v,int thick,unsigned char col);

void cgm_clear(CGM *c,unsigned char *s)
{
    memset(s,0,XS*YS);
}

void cgm_render(CGM *c,unsigned char *s,
                void (*trans)(int x,int y,int *xx,int *yy))
{
    int     n,i,ver[6];
    ELEMENT *ele;

    ele=c->head;
    while(ele!=NULL)
    {
        if(ele->types&CGM_POLYGON)
        {
            for(n=0;n<ele->tris;n++)
            {
                for(i=0;i<6;i+=2)
                {
                    trans(ele->trisv[n*6+i],ele->trisv[n*6+i+1],
                          &ver[i],&ver[i+1]);
                }
                cgm_tri(s,ver,ele->color);
            }
        }
        if(ele->types&CGM_POLYLINE)
        {
            for(n=0;n<ele->points-1;n++)
            {
                for(i=0;i<4;i+=2)
                {
                    trans(ele->pointsv[n*2+i],ele->pointsv[n*2+i+1],
                          &ver[i],&ver[i+1]);
                }
                cgm_line(s,ver,ele->linewidth,ele->linecolor);
            }
        }

        ele=ele->next;
    }
}

void cgm_tri(unsigned char *s,int *v,unsigned char col)
{
    static int left[YS],right[YS];
    int maxy=-100000,miny=100000,
        sx,sy,ex,ey,dx,
        tmp,n,i,
        lef,rig;

    for(n=1;n<6;n+=2)
    {
        if(v[n]<miny)
            miny=v[n];
        if(v[n]>maxy)
            maxy=v[n];
    }
    miny=(miny+2)>>2;
    maxy=(maxy+2)>>2;
    if(miny<0) miny=0;
    if(maxy>=YS) maxy=YS-1;

    for(n=miny;n<=maxy;n++)
    {
        left[n]=10000*65536;
        right[n]=-10000*65536;
    }

    /* Fill edge buffers */
    for(n=0;n<6;n+=2)
    {
        sx=v[n];       sy=(v[n+1]+2)>>2;
        ex=v[(n+2)%6]; ey=(v[(n+3)%6]+2)>>2;

        if(sy>ey)
        {
            tmp=sx; sx=ex; ex=tmp;
            tmp=sy; sy=ey; ey=tmp;
        }
        if(sy==ey)
            continue;

        dx=(ex-sx)*16384/(ey-sy);
        sx<<=14; ex<<=14;

        tmp=(ey>maxy)?maxy:ey;
        for(i=sy;i<=tmp;i++,sx+=dx)
        {
            if(i<0 || i>=YS)
                continue;

            if(sx<left[i])
                left[i]=sx;
            if(sx>right[i])
                right[i]=sx;
        }
    }

    for(n=miny;n<=maxy;n++)
    {
        lef=(left[n]+32767)>>16;
        rig=(right[n]+32767)>>16;
        
        if(rig<0) continue;
        if(lef>=XS) continue;

        if(lef<0) lef=0;
        if(rig>=XS) rig=XS-1;

        //for(i=lef;i<=rig;i++)
        //    s[n*XS+i]=col;
        memset(&s[n*XS+lef],col,rig-lef+1);
    }
}

void cgm_dot(unsigned char *s,int x,int y,unsigned char col)
{
    x=(x+2)>>2;
    y=(y+2)>>2;
    if(x<XS && x>=0 && y<YS && y>=0)
        s[y*XS+x]=col;
}

/* Now this is pretty BAD */
void cgm_line(unsigned char *s,int *v,int thick,unsigned char col)
{
    int sx,sy,ex,ey,dx,dy,
        n,i,tmp;

    sx=v[0]; sy=v[1];
    ex=v[2]; ey=v[3];

    if(sx==ex && sy==ey)
    {
        cgm_dot(s,sx,sy,col);
        return;
    }

    dx=ex-sx;
    dy=ey-sy;

    if(abs(dx)>abs(dy)) /* Inc X */
    {
        if(sx>ex)
        {
            tmp=sx; sx=ex; ex=tmp;
            tmp=sy; sy=ey; ey=tmp;
            dx=-dx;
        }
        sy=(sy<<14)+8192; ey=(ey<<14)+8192;
        dy=(ey-sy)/dx;
        if(thick==1)
            for(n=sx;n<=ex;n++,sy+=dy)
                cgm_dot(s,n,sy>>14,col);
        else
            for(n=sx;n<=ex;n++,sy+=dy)
                for(i=0;i<thick;i++)
                    cgm_dot(s,n,i*4-thick*2+(sy>>14),col);
    }
    else /* Inc Y */
    {
        if(sy>ey)
        {
            tmp=sx; sx=ex; ex=tmp;
            tmp=sy; sy=ey; ey=tmp;
            dy=-dy;
        }
        sx=(sx<<14)+8192; ex=(ex<<14)+8192;
        dx=(ex-sx)/dy;
        if(thick==1)
            for(n=sy;n<=ey;n++,sx+=dx)
                cgm_dot(s,sx>>14,n,col);
        else
            for(n=sy;n<=ey;n++,sx+=dx)
                for(i=0;i<thick;i++)
                    cgm_dot(s,i*4-thick*2+(sx>>14),n,col);
    }
}
