

#include "starfield.h"



/*--- Starfield stuff. ---*/
typedef struct _star_t
{
    /* Enable/disable switch. */
    unsigned char enabled;
    /* Animation speed (0:slow, 255:fast) */
    unsigned char speed;

    /* graphics ID (linked with star_gfx_t stuff). */
    int gfx_id;
    /* Current position, 24:8 fixed point. */
    int x, y;
    /* Display width and height, 24:8 fixed point. */
    int w, h;
} star_t;
typedef struct _star_gfx_t
{
    /* Pointer to data in VDP1 RAM. */
    unsigned char* ptr;
    /* Width and height. */
    int w, h;
} star_gfx_t;

#define STARSGFX_MAXCOUNT 8
#define STARS_MAXCOUNT    200
typedef struct _starfield_t
{
    /* Area where to display star field. */
    int x0, x1, y0, y1;
    /* Animation center. (0~100, 50 is the display rect's center) */
    int cx, cy;
    /* Target stars count (this is a command value, can be different from the stars count.) */
    int stars_count_tgt;


    /* The stars data graphics. */
    int gfx_count;
    star_gfx_t gfx[STARSGFX_MAXCOUNT];

    /* The stars data. */
    int stars_count;
    star_t stars[STARS_MAXCOUNT];
} starfield_t;

/* Our starfield data. */
starfield_t  _sf_data;
starfield_t* _sf;


void sf_delete_star(int id)
{
    if(_sf->stars[id].enabled)
    {
        /* Disable the selected star. */
        _sf->stars[id].enabled = 0;
        /* Update star count. */
        _sf->stars_count--;
    }
}
void sf_add_star(int add_in_center)
{
    int i, tmp;
    star_t* s;

    /* Can't add ? */
    if(_sf->stars_count >= STARS_MAXCOUNT)
    {
        return;
    }

    for(i=0; i<STARS_MAXCOUNT; i++)
    {
        s = _sf->stars + i;
        if(s->enabled == 0)
        {
            /* Found free star, so use it. */
            s->enabled = 1;

            /* Set a new star. */
            s->gfx_id = rand() % (_sf->gfx_count);
            if(add_in_center)
            {
                tmp = _sf->x0 + ((_sf->x1 - _sf->x0)*3)/8 + rand()%((_sf->x1 - _sf->x0)/4); s->x = tmp << 8;
            }
            else
            {
                tmp = _sf->x0 + rand()%(_sf->x1 - _sf->x0); s->x = tmp << 8;
            }

            if(add_in_center)
            {
                tmp = _sf->y0 + ((_sf->y1 - _sf->y0)*3)/8 + rand()%((_sf->y1 - _sf->y0)/4); s->y = tmp << 8;
            }
            else
            {
                tmp = _sf->y0 + rand()%(_sf->y1 - _sf->y0); s->y = tmp << 8;
            }
            tmp = _sf->gfx[s->gfx_id].w; s->w = tmp << 8;
            tmp = _sf->gfx[s->gfx_id].h; s->h = tmp << 8;
            s->speed = rand()%256;
            _sf->stars_count++;
        }
    }
}




void sf_make_star(unsigned short* ptr, int w, int h, unsigned short col1, unsigned short col2)
{
    ptr[0*w + 0] = TRANSCOLOR;
    ptr[0*w + 1] = TRANSCOLOR;
    ptr[0*w + 2] = TRANSCOLOR;
    ptr[0*w + 3] = col2;
    ptr[0*w + 4] = TRANSCOLOR;
    ptr[0*w + 5] = TRANSCOLOR;
    ptr[0*w + 6] = TRANSCOLOR;
    ptr[0*w + 7] = TRANSCOLOR;

    ptr[1*w + 0] = TRANSCOLOR;
    ptr[1*w + 1] = TRANSCOLOR;
    ptr[1*w + 2] = col2;
    ptr[1*w + 3] = col1;
    ptr[1*w + 4] = col2;
    ptr[1*w + 5] = TRANSCOLOR;
    ptr[1*w + 6] = TRANSCOLOR;
    ptr[1*w + 7] = TRANSCOLOR;

    ptr[2*w + 0] = TRANSCOLOR;
    ptr[2*w + 1] = TRANSCOLOR;
    ptr[2*w + 2] = TRANSCOLOR;
    ptr[2*w + 3] = col2;
    ptr[2*w + 4] = TRANSCOLOR;
    ptr[2*w + 5] = TRANSCOLOR;
    ptr[2*w + 6] = TRANSCOLOR;
    ptr[2*w + 7] = TRANSCOLOR;
}



void sf_init(void)
{
    unsigned short* ptr = (unsigned short *)0x25C40000;
    int i, w, h;

    _sf = &_sf_data;

    /*-- Reset all data. --*/
    memset((void*)_sf, 0, sizeof(starfield_t));

    /*-- Set graphics table. --*/
    _sf->gfx_count = 4;
    for(i=0; i<_sf->gfx_count; i++)
    {
        switch(i)
        {
            default:
            case(0):
                /* Star graphics #1: red star (8x3 size). */
                w = 8; h = 3;
                sf_make_star(ptr, w, h, COLOR(15, 0, 0), COLOR( 7, 0, 0));
                break;

            case(1):
                /* Star graphics #2: blue star (8x3 size). */
                w = 8; h = 3;
                sf_make_star(ptr, w, h, COLOR( 0, 0,15), COLOR( 0, 0, 7));
                break;

            case(2):
                /* Star graphics #2: white star (8x3 size). */
                w = 8; h = 3;
                sf_make_star(ptr, w, h, COLOR(31,31,31), COLOR(15,15,15));
                break;

            case(3):
                /* Star graphics #2: orange star (8x3 size). */
                w = 8; h = 3;
                sf_make_star(ptr, w, h, COLOR(31,20, 0), COLOR(15,10, 0));
                break;
        }

        /* Set width and height. */
        _sf->gfx[i].w = w;
        _sf->gfx[i].h = h;
        /* Set and increment pointer to graphics data. */
        _sf->gfx[i].ptr = (unsigned char*)ptr;
        ptr += w*h; // Note: address must be a multiple of 8 bytes.
    }
    for(i=_sf->gfx_count; i<STARSGFX_MAXCOUNT; i++)
    {
        /* Set width and height. */
        _sf->gfx[i].w   = _sf->gfx[_sf->gfx_count-1].w;
        _sf->gfx[i].h   = _sf->gfx[_sf->gfx_count-1].h;
        _sf->gfx[i].ptr = _sf->gfx[_sf->gfx_count-1].ptr;
    }
    /* Make Gouraud shading table */
    ptr = (unsigned short *)0x25C60000;
    ptr[0] = COLOR(31, 0, 0);
    ptr[1] = COLOR( 0,31, 0);
    ptr[2] = COLOR( 0, 0,31);
    ptr[3] = COLOR(31,31,31);


    /*-- Specify display rect. --*/
    _sf->x0 = 0;
    _sf->x1 = 319;
    _sf->y0 = 0;
    _sf->y1 = 223;


    /*-- Specify the target stars count. --*/
    _sf->stars_count_tgt = STARS_MAXCOUNT;

    /*-- Set animation center. --*/
    _sf->cx = 50; // Value is a percentage.
    _sf->cy = 50; // Value is a percentage.


    /*-- Generate the initial stars. --*/
    for(i=0; i<_sf->stars_count_tgt; i++)
    {
        sf_add_star(0/*add_in_center*/);
    }

}

/* Minimal pitch (fixed point value). */
#define MINPITCH 3
void sf_animate(void)
{
    star_t* s;
    int i, j, tmp;

    /* Animation center (fixed value). */
    int c[2];
    /* Object position and display range (fixed value). */
    int pc, p0, p1;
    /* Distance to animation center (fixed value). */
    int d;
    /* Animation pitch (fixed value). */
    int pitch;


    /* Need to generate new star ? */
    tmp = _sf->stars_count_tgt - _sf->stars_count;
    if(tmp > 0)
    {
        if((rand()%100) < (20 + tmp * 3))
        {
            sf_add_star(1/*add_in_center*/);
        }
    }


    /* Compute animation center (fixed point values). */
    c[0] = (_sf->x0 + ((_sf->x1 - _sf->x0) * _sf->cx) / 100) << 8;
    c[1] = (_sf->y0 + ((_sf->y1 - _sf->y0) * _sf->cy) / 100) << 8;

    /* Animate each stars. */
    for(i=0; i<STARS_MAXCOUNT; i++)
    {
        s = _sf->stars + i;
        if(s->enabled)
        {
            for(j=0; j<2; j++)
            {
                pc = (j==0 ? s->x : s->y);
                p0 = (j==0 ? _sf->x0 : _sf->y0);
                p1 = (j==0 ? _sf->x1 : _sf->y1);

                d = pc - c[j];
                pitch = (d * (110 + 9*s->speed)) / 20000;
                /* Avoid null pitch values. */
                if(d > 0)
                {
                    if(pitch < MINPITCH)
                    {
                        pitch = MINPITCH;
                    }
                }
                else
                {
                    if(pitch > -MINPITCH)
                    {
                        pitch = -MINPITCH;
                    }
                }

                if(j==0)
                {
                    s->x += pitch;
                }
                else
                {
                    s->y += pitch;
                }
            }
            /* Out of display range ? */
            if( ((s->x + s->w) < (_sf->x0 << 8))
            ||  ((s->x       ) > (_sf->x1 << 8))
            ||  ((s->y + s->h) < (_sf->y0 << 8))
            ||  ((s->y       ) > (_sf->y1 << 8)) )
            {
                sf_delete_star(i);
                if(i != 0) i--;
            }
        }
    }

    /* Log currently displayed stars count. */
    scd_msgout(2, "[SF]_sf->stars_count=%d (tgt=%d)", _sf->stars_count, _sf->stars_count_tgt);
}

void sf_draw(void)
{
    int i;
    star_t* s;
    star_gfx_t* g;

    for(i=0; i<STARS_MAXCOUNT; i++)
    {
        s = _sf->stars + i;
        if(s->enabled)
        {
            g = _sf->gfx + s->gfx_id;
            vdp1_add_distorted_sprite(
                (s->x     )>>8, (s->y     )>>8, 
                (s->x+s->w)>>8, (s->y     )>>8, 
                (s->x+s->w)>>8, (s->y+s->h)>>8, 
                (s->x     )>>8, (s->y+s->h)>>8, 
                (((unsigned long)g->ptr) & 0xFFFFF)>>3, g->w, g->h);
        }
    }

}

