/*
    Background and window example
    by Charles MacDonald
    WWW: http://cgfm2.emuviews.com

    Shows four backgrounds using 16x16 4-bit tiles within specific areas of
    the screen through the use of both windows.

    Press START to return to the ARP menu
*/

#include "shared.h"
#include <math.h>


/***************************************************************************
 *                         Yeti3D engine stuff                             *
 ***************************************************************************/

#include "src/game.h"
yeti_t yeti;
cell_t yeti_cells[YETI_MAP_HEIGHT * YETI_MAP_WIDTH];



/*
** Name: yeti_load_rom_sat
** Desc: Load ROM file from CD-ROM.
**
** (function similar to yeti_load_rom, but designed for Saturn only.)
** The purpose of "Saturn only" is to limit the usage of
** memory as well as using HRAM as much as possible.
*/
unsigned long yeti_load_rom_sat(char* filename)
{
    sc_file_t* fh1 = NULL;
    unsigned long ret;
    unsigned long i, len;
    unsigned short tmp;
    unsigned short* src;
    unsigned short* dst;
    int x, y;

    /**
     * Static allocation of memory for yeti data.
     * todo1: use sc_malloc in order to use HRAM when it is possible, or LRAM/Cartridge when it is not.
     * todo2: load cell data chuk by chunk in order to minimize buffer size.
    **/
    yeti_t* yt = &yeti;
    /* Buffer used in order to load data from CD-ROM. */
    unsigned char* load_buffer_ptr = (unsigned char*)0x00200000;
    unsigned long  load_buffer_len = 512*1024; // LRAM first half
    /* Cells data (results of the conversion from ROM cell data). */
    unsigned char* cells_ptr = (unsigned char*)(0x00200000 + 512*1024);
    unsigned long  cells_len = 512*1024; // LRAM second half
    /* Textures on VDP1 RAM. */
    unsigned char* textures_ptr = (unsigned char*)0x25C40000;
    unsigned long  textures_len = 128*1024; // Gouraud data starts from 0x25C40000


    /* Reset yeti data. */
    //yeti_init(&yeti, /*&framebuffer*/NULL, /*&framebuffer*/NULL, textures, palette, NULL/*lua*/);
    //yeti_reset(&yeti, yeti_cells, NULL/*framebuffer*/, NULL/*lua*/);
    yeti_reset(yt, yeti_cells, YETI_MAP_HEIGHT, YETI_MAP_WIDTH, (unsigned char *)0x25C40000/*tex*/, 128*1024/*tex_len*/, NULL/*framebuffer*/, NULL/*lua*/);
    if(filename == NULL)
    {/* No file to load ? -> exit */
        return 1;
    }



    /* Read the entire ROM data from CD-ROM. */
    scd_logout("fopen ...", 0); //scd_logflush();
    fh1 = sc_fopen(SC_FILE_CDROM, filename);
    scd_logout("handle1 = %d", fh1);
    ret = sc_fread(fh1, 0/*offset*/, load_buffer_len/*size*/, (void*)load_buffer_ptr/*buff*/);
    scd_logout("READ1 = %d bytes", ret); //scd_logflush();
    sc_fclose(fh1);

    if(ret != 0)
    {
        /* Read header data. */
        scd_logout("yeti_header_init start", 0);
        yeti_header_init(yt, (rom_header_t*)load_buffer_ptr);
        scd_logout("yeti_header_init end", 0);


        /* Copy textures to RAM. */
        yt->tex_data     = textures_ptr;
        yt->tex_data_len = textures_len;
        scd_logout("CopyTEX: yeti->tex_data   = 0x%08X", yt->tex_data);
        scd_logout("CopyTEX: ROM              = 0x%08X", load_buffer_ptr);
        scd_logout("CopyTEX: yeti->tex_offset = 0x%08X", yt->tex_offset);
        scd_logout("CopyTEX: yeti->tex_len    = 0x%08X", yt->tex_len);


        /* Swap data while copying textures to vram. */
        src = (unsigned short*)((u8*)(load_buffer_ptr) + yt->tex_offset);
        dst = (unsigned short*)yt->tex_data;
        len = yt->tex_len/2;
        for(i=0; i<len; i++)
        {
            tmp = *src;
            *dst = ((tmp<<8)&0xFF00) | ((tmp>>8)&0x00FF);
            src++;
            dst++;
        }
        scd_logout("yeti_textures_init start", 0);
        yeti_textures_init(yt, yt->tex_data, yt->tex_len);
        scd_logout("yeti_textures_init end", 0);


        /* Copy and init cell data. */
        yt->cells_data = (cell_t*)cells_ptr;
        yt->cells_rows = YETI_MAP_HEIGHT;
        yt->cells_cols = cells_len / (YETI_MAP_HEIGHT * sizeof(cell_t));
        scd_logout("yeti_map_init start", 0);
        yeti_map_init(yt, (rom_cell_t*)((u8*)(load_buffer_ptr) + yt->map_offset));
        scd_logout("yeti_map_init end", 0);

        /* Init game. */
        scd_logout("game_init start", 0);
        game_init(yt);
        scd_logout("game_init end", 0);



        /* Init camera. */
        scd_logout("Init camera ...", 0);
        yt->camera->x = i2f(yt->map_width  / 2) + FIXHALF;
        yt->camera->y = i2f(yt->map_height / 2) + FIXHALF;
        for (y = 0; y < yt->map_height; y++)
        {
            for (x = 0; x < yt->map_width; x++)
            {
                if (yt->cells[y][x].ent == 1)
                {
                    yt->camera->x = i2f(x) + FIXHALF;
                    yt->camera->y = i2f(y) + FIXHALF;
                }
            }
        }
        yt->camera->t = 0;
        yt->camera->r = 0;
        yt->camera->p = i2f(256);



        //// Display yeti data contents
        //yeti_logout("--------------------------------", 0);
        //for(i=0; i<YETI_MAP_HEIGHT; i++)
        //{
        //    yeti_logout("yeti->cells[%d] = 0x%08X", i, yeti->cells[i]);
        //}
        //yeti_logout("", 0);
        //yeti_logout("yeti->map_height = %d", yeti->map_height);
        //yeti_logout("yeti->map_width = %d", yeti->map_width);
        //for (y = 0; y < yeti->map_height; y++)
        //{
        //    for (x = 0; x < yeti->map_width; x++)
        //    {
        //    yeti_logout(" yeti->cells[%d][%d].ttx = %d", x, y, yeti->cells[y][x].ttx);
        //    }
        //}
        //
        //for(i=0; i<YETI_TEXTURE_MAX; i++)
        //{
        //    yeti_logout("  yeti->tex_table[%d] = 0x%08X", i, yeti->tex_table[i]);
        //}
    }

    return ret;
}

/***************************************************************************
 *                       Yeti3D engine stuff - end                         *
 ***************************************************************************/






void _main(void)
{
    unsigned short *p;
    unsigned char frame_count = 0;
    int i;
    pad_t pad;
    unsigned short temp;
    char* levels_list[] = { "void level"       , "MAPS/DEFAULT.YAD" , 
        "MAPS/TECH32.YAD" , "MAPS/D1_E1M1.YAD" , "MAPS/D2_E1M1.YAD" , 
        "MAPS/D3_E1M1.YAD", "MAPS/FAG_E1M1.YAD", "MAPS/TEST0.YAD"   , 
        "MAPS/TEST1.YAD"  , "MAPS/TEST2.YAD"   , "MAPS/TEST3.YAD"   , 
        "MAPS/TESTES.YAD" , NULL};
    int level_index = 0;






    dbg_init();

    /* SatCom: initialization. */
    sc_init();


    vdp_init();
    cio_init();
    pad_init();


    /* Set up VDP1 to appear under VDP2 graphics (0=hide, 1-7=visible) */
    // PRISA = 0x0101;
    // PRISB = 0x0101;
    // PRISC = 0x0101;
    // PRISD = 0x0101;

    /* Set up VDP1 registers */
    // TVMR = 0x0000;
    // FBCR = 0x0000;
    // PTMR = 0x0002;
    EWDR = COLOR(7,7,7);    /* Erase color: gray */
    EWLR = 0x0000;          /* Erase range: (0,0) -> (352,240) */
    EWRR = 0x50DF;



    /* Screen on */
    TVMD = 0x8000;


    /* Start Filling VDP1 command list with buffer common stuff. */
    vdp1_add_system_clip(320, 224);
    vdp1_add_user_clip(0, 0, 319, 223);
    vdp1_add_local_coords(0, 0);

    /* Erase screen (needed because polygons from the previous frame remain on the screen). */
    vdp1_add_polygon(0, 0, 319, 0, 319, 223, 0, 223, COLOR(7,7,7), 0);
    /* Set VDP1 command list stuff. */
    vdp1_mesh(0);
    vdp1_start(2/*double buffering*/, 2000/*max commands count.*/);




    /* Print message */
    //cio_printf(2, 1, COLOR_WHITE, "Yeti3D demo 1.0b3 - Not for release");
    cio_printf(2, 1, COLOR_WHITE, "Yeti3D demo - S.A.T.U.R.N contest ");
    cio_printf(2, 2, COLOR_YELLOW, "Build on " RELEASE_DATE);
    // cio_printf(2, 2, COLOR_RED, "by Charles MacDonald");
    // cio_printf(2, 3, COLOR_PURPLE, "WWW: http://cgfm2.emuviews.com");


    /* Yeti3D test */
    for(i=0; i<128; i++)
    {
        reciprocal[i] = (128-i) + reciprocal[128];
    }

    cio_printf(2, 10, COLOR_LIME, "Yeti init ...   ");
    yeti_load_rom_sat(NULL);
    cio_printf(2, 10, COLOR_LIME, "Yeti init OK !  ");

    //cio_printf(2, 10, COLOR_LIME, "Game init ...   ");
    //game_init(&yeti);
    //yeti_default_lighting(&yeti); 


    /* Make Gouraud shading table */
    p = (unsigned short *)0x25C60000;
    p[0] = COLOR(31, 0, 0);
    p[1] = COLOR( 0,31, 0);
    p[2] = COLOR( 0, 0,31);
    p[3] = COLOR(31,31,31);


    /* Go to position we want to debug. */
    yeti.camera->x = YETI_DEFPOS_X;
    yeti.camera->y = YETI_DEFPOS_Y;
    yeti.camera->z = YETI_DEFPOS_Z;
    yeti.camera->t = YETI_DEFPOS_T;
    yeti.camera->r = YETI_DEFPOS_R;
    yeti.camera->p = YETI_DEFPOS_P;

    cio_printf(2, 10, COLOR_LIME, "                ");
    cio_printf(2, 26, COLOR_WHITE, "Push L, R or C button to load a map ! ");

    /* Main loop */
    for(;;)
    {
        unsigned long poly_cnt;

        /*- VDP1 stuff ----------------------------------------------------------------*/
        /* Update TVMR */
        temp = 0x0000;
        //if(pad.new & PAD_A) temp |= 0x0004;
        //if(pad.new & PAD_B) temp |= 0x0002;
        //if(pad.new & PAD_C) temp |= 0x0001;
        TVMR = temp;


        /* Update TVMD */
        temp = 0x8000;
        //if(pad.new & PAD_LBUTTON) temp |= 0x00C0;
        //if(pad.new & PAD_RBUTTON) temp |= 0x0002;
        TVMD = temp;

        /* Update FBCR */
        /* About the 2 last bits (VDP1 user's manual, chap 4.2) :
         *  - if set to 0, drawing is done only for the polygons that can be displayed during 1/60s
         *  - if set to 3, drawing is done for all the polygon list, use if you are doing something huge (or bad-coded)
         */
        FBCR = 0x0003;
        //if(pad.new & PAD_Y) fbcr |= 0x0008;
        //if(pad.new & PAD_Z)
        //{
        //    fbcr |= 0x0004;
        //}

        /* Update EWRR */
        EWRR = /*(pad.new & PAD_X) ? 0x0101 : */0x50DF;
        /*- VDP1 stuff ----------------------------------------------------------------*/



        /* Bump frame counter */
        scd_msgout(1, "Frame ID=%02X", frame_count);
        frame_count++;

        /* SatCom: if needed, transfer data. */
        sc_check();

        /* Wait for V-Blank. */
        wait_vblank_out();
        wait_vblank_in();


        /* Poll joypad */
        pad_read(&pad);

        /* Start - Quit program */
        if(pad.new & PAD_START)
        { /* Exit to multiplayer. */
            int (*pFun)(void);
            pFun = (int(*)(void))0x600026C;
            (*pFun)();
        }

        /*! Debug stuff. */
        // if(pad.delta & PAD_Z)
        // {
            // _dbg.on = 1 - _dbg.on;

            // _dbg.draw_start = 0;
            // _dbg.draw_len = (_dbg.on ? 100 : 0xFFFFFFFF);
            // _dbg.log = _dbg.on;
        // }

        if(_dbg.on)
        { /*! Debug stuff */
            cio_printf(2, 16, COLOR_BG_FG(COLOR_PURPLE, COLOR_GREEN), "DBG ", 0);
            if(pad.new & PAD_LEFT)  _dbg.draw_start--;
            if(pad.new & PAD_RIGHT) _dbg.draw_start++;

            if(pad.new & PAD_A)     _dbg.draw_len = 10;
            if(pad.new & PAD_DOWN)  _dbg.draw_len--;
            if(pad.new & PAD_UP)    _dbg.draw_len++;
            scd_logout("draw_start=%d, draw_len=%d", _dbg.draw_start, _dbg.draw_len);
        }
        else
        {
            //cio_printf(2, 16, COLOR_GREEN, "EXEC", 0);

            /* Send key codes to yeti engine. */
            yeti.keyboard.up     = (pad.new & PAD_UP    ? 1 : 0);
            yeti.keyboard.down   = (pad.new & PAD_DOWN  ? 1 : 0);
            yeti.keyboard.left   = (pad.new & PAD_LEFT  ? 1 : 0);
            yeti.keyboard.right  = (pad.new & PAD_RIGHT ? 1 : 0);
            yeti.keyboard.a      = (pad.new & PAD_A     ? 1 : 0);
            yeti.keyboard.b      = (pad.new & PAD_B     ? 1 : 0);
            yeti.keyboard.l      = (pad.new & PAD_X     ? 1 : 0);
            yeti.keyboard.r      = (pad.new & PAD_Y     ? 1 : 0);
            yeti.keyboard.select = (pad.new & PAD_Z     ? 1 : 0);
        }

        ///* Test CD-ROM. */
        //if(pad.delta & PAD_C)
        //{
        //    cio_printf(2, 26, COLOR_WHITE, " Read ABS.TXT ...                     ");
        //
        //    sc_file_t* fh1 = NULL;
        //    unsigned long ret;
        //    fh1 = sc_fopen(SC_FILE_CDROM, "ABS.TXT");
        //    unsigned long s1 = sc_fsize(fh1);
        //    char buff[30];
        //    memset((void*)buff, '\0', sizeof(buff));
        //    ret = sc_fread(fh1, 0/*offset*/, sizeof(buff)-1/*size*/, (void*)buff/*buff*/);
        //    if(ret != 0)
        //    {
        //        cio_printf(10, 26, COLOR_WHITE, "(%d) %s", s1, buff);
        //    }
        //}

        /* Test ROM loading. */
        if((pad.delta & PAD_LBUTTON) || (pad.delta & PAD_RBUTTON)
        || (pad.delta & PAD_C      ))
        {
            unsigned long ret = 0;
            int load_level = 1;

            /* Erase the yeti stuff. */
            vdp1_flip();

            /* Set new level index. */
            if(pad.delta & PAD_RBUTTON)
            {
                if(levels_list[level_index+1] == NULL)
                {
                    level_index = 0;
                }
                else
                {
                    level_index++;
                }
            }
            else if(pad.delta & PAD_C)
            {
                int i, n, l = level_index;
                for(i=0; i<20; i++)
                {
                    cio_printf(2, i+6, COLOR_WHITE, "                                      ");
                }
                n = 0;
                while(levels_list[n+1] != NULL) {n++;}
                do
                {
                    /* SatCom: if needed, transfer data. */
                    sc_check();

                    /* Wait for V-Blank. */
                    wait_vblank_out();
                    wait_vblank_in();


                    /* Poll joypad */
                    pad_read(&pad);

                    /* Start - Quit program */
                    if(pad.new & PAD_START)
                    { /* Exit to multiplayer. */
                        int (*pFun)(void);
                        pFun = (int(*)(void))0x600026C;
                        (*pFun)();
                    }


                    if((pad.delta & PAD_UP) || (pad.new & PAD_LEFT))
                    {
                        l = (l != 0 ? l-1 : n-1);
                    }
                    else if((pad.delta & PAD_DOWN) || (pad.new & PAD_RIGHT))
                    {
                        l = (l != (n-1) ? l+1 : 0);
                    }

                    cio_printf(2, 6, COLOR_YELLOW, "         --- Select level ---         ");
                    for(i=0; i<n; i++)
                    {
                        cio_printf(2, i+7, (i==l ? COLOR_BG_FG(COLOR_RED, COLOR_WHITE) : COLOR_WHITE), "%s", levels_list[i]);
                    }
                }
                while(!((pad.delta & PAD_A) || (pad.delta & PAD_B) || (pad.delta & PAD_C)) );
                for(i=0; i<20; i++)
                {
                    cio_printf(2, i+6, COLOR_WHITE, "                                      ");
                }
                if((pad.delta & PAD_A) || (pad.delta & PAD_C))
                {
                    level_index = l;
                }
                else
                {
                    load_level = 0;
                }
            }
            else
            {
                if(level_index != 0)
                {
                    level_index--;
                }
                else
                {
                    while(levels_list[level_index+1] != NULL)
                    {
                        level_index++;
                    }
                }
            }


            /* Load selected level. */
            if(load_level)
            {
                cio_printf(2, 26, COLOR_WHITE, "                                      ");
                cio_printf(2, 26, COLOR_WHITE, "Loading %s ... ", levels_list[level_index]);
                ret = yeti_load_rom_sat((level_index == 0 ? NULL : levels_list[level_index]));
                if(level_index == 6)
                { // Q&D ...
                    //(&yeti)->camera->x = i2f(0) + FIXHALF;
                    //(&yeti)->camera->y = i2f(0) + FIXHALF;
                    (&yeti)->camera->x =  3300;
                    (&yeti)->camera->y = 12000;
                }
                if(ret != 0)
                {
                    cio_printf(2, 26, COLOR_WHITE, "                                      ");
                    cio_printf(2, 26, COLOR_WHITE, "%s loaded !", levels_list[level_index]);
                }
            }
        }


        game_loop(&yeti);
        /* End drawing. */
        //poly_cnt = vdp1_list_get_index();
        poly_cnt = vdp1_flip();



        /* Print VDP1 status registers */
        //cio_printf(2, 5, COLOR_LIME, "EDSR=0x04X", EDSR);
        //cio_printf(2, 6, COLOR_LIME, "LOPR=0x%08X", LOPR<<3);
        //cio_printf(2, 7, COLOR_LIME, "COPR=0x%08X", COPR<<3);
        //cio_printf(2, 8, COLOR_LIME, "MODR=0x%04X", MODR);

        /* Display camera position. */
        cio_printf(2, 18, COLOR_YELLOW, "CAMX=%7d", yeti.camera->x);
        cio_printf(2, 19, COLOR_YELLOW, "CAMY=%7d", yeti.camera->y);
        cio_printf(2, 20, COLOR_YELLOW, "CAMZ=%7d", yeti.camera->z);
        cio_printf(2, 21, COLOR_YELLOW, "CAMT=%7d", yeti.camera->t);
        cio_printf(2, 22, COLOR_YELLOW, "CAMR=%7d", yeti.camera->r);
        cio_printf(2, 23, COLOR_YELLOW, "CAMP=%7d", yeti.camera->p);

        scd_msgout(MSG_POLYCNT, "Poly=%d", poly_cnt);
        cio_printf(2, 25, COLOR_WHITE, "Poly=%5d", poly_cnt);
    }

    vdp_shutdown();
    pad_shutdown();
}


