/******************************************************************************
 * mach64 Chapter 7 sample code                                               *
 *                                                                            *
 * sbufp.c - This program performs a simple animation.  Synchronization       *
 * is achieved by polling the vertical blank bit of the CRTC_INT_CNTL         *
 * register.  The animation frames use a single buffer.                       *
 *                                                                            *
 * Copyright (c) 1994-1998 ATI Technologies Inc.  All rights reserved.        *
 ******************************************************************************/

#include <stdio.h>
#include <i86.h>
#include "..\util\atim64.h"
#include "..\util\defines.h"
#include "..\util\main.h"
#include "..\util\vtga.h"

#define BACKGROUND_COLOUR   0xFF
#define NUMFRAMES           20


/******************************************************************************
 * Main Program to demonstrate single buffer animation with polling sync.     *
 *  Function: demonstrate single buffer animation with polling sync.          *
 *    Inputs: Arguments for mode spatial and colour resolution                *
 *   Outputs: NONE                                                            *
 ******************************************************************************/

void main (int argc, char *argv[])
{
    char filename[20];
    TARGA_HEADER header;
    short width, height;
    short srcx, srcy;
    short savex, savey;
    short i, j;
    short y_draw;
    short frame;
    short frames;
    short framesperwidth;
    short topline;
    short step;
    point points[NUMFRAMES];
    short reg1;

    printf ("mach64 Chapter 7 sample code\n"
            "\n"
            "sbufp.c\n"
            "This program performs a simple amination.  Synchronization\n"
            "is achieved by polling the vertical blank bit of the CRTC_INT_CNTL\n"
            "register.  The animation frames use a single buffer.\n"
            "\n"
            "This program is only available in 8bpp pixel depth.\n"
            "Spatial resolution (640, 800, 1024, 1280, 1600) should be passsed as\n"
            "an argument. Default setting is 640x480 spatial resolution.\n");

    // Batch command to detect the mach64, perform a hardware query, Save old
    // mode information, process mode info arguments, load and set mode, enable
    // aperture, set up palettes, initialize engine to known state, and reset
    // all engine queues.

    start (argc, argv);
    clear_screen (0, 0, MODE_INFO.xres, MODE_INFO.yres);

    // Make sure we are in 8bpp mode.
    if (MODE_INFO.bpp != 8)
    {
        // Disable accelerator mode and switch back to VGA text mode.

        finish ();
        printf ("SBUFP requires colour depth of 8 bpp.\n");
        exit (1);
    } // if

    // Get targa header information.
    if (get_targa_header ("..\\image\\frame1.tga", &header) != SUCCESS)
    {
        finish ();
        printf ("Error reading targa file header information.\n");
        exit (0);
    } // if

    // Setup image size, source area, save area, and position increment.
    width = header.width;
    height = header.height;
    srcx = 0;
    srcy = MODE_INFO.yres + height;
    savex = 0;
    savey = MODE_INFO.yres;
    y_draw = (MODE_INFO.yres - height)/2;
    step = 2;

    // Determine how large to expand the scissors.
    frames = NUMFRAMES;
    framesperwidth = MODE_INFO.xres / width;
    topline = frames / framesperwidth;
    if ((topline * framesperwidth) != frames)
    {
        topline++;
    } // if
    topline = ((topline + 1) * height) + MODE_INFO.yres;

    // Expand scissors to include source and save areas.
    wait_for_fifo (4);
    regw (SC_LEFT, 0);
    regw (SC_TOP, 0);
    regw (SC_RIGHT, MODE_INFO.xres - 1);
    regw (SC_BOTTOM, topline - 1);

    // Draw background the same as the image background.
    regw (DP_FRGD_CLR, BACKGROUND_COLOUR);
    draw_rectangle (0, 0, MODE_INFO.xres, MODE_INFO.yres);

    // Load source images into off-screen memory for frame blitting and
    // record their position.
    frame = 0;
    i = 0;
    j = 0;
    while (frame < frames)
    {
        // Record each frame coordinate.
        points[frame].x = srcx + (width * i);
        points[frame].y = srcy + (height * j);

        // Load next frame image into video memory.
        sprintf (filename, "..\\image\\frame%d.tga", frame + 1);
        if (load_targa (filename, points[frame].x, points[frame].y) != SUCCESS)
        {
            finish ();
            printf ("Error loading targa file to memory.\n");
            exit (1);
        } // if

        // Adjust location of frame load coordinate as necessary.
        frame++;
        i++;
        if (i > ((MODE_INFO.xres / header.width) - 1))
        {
            i = 0;
            j++;
        } // if
    } // while

    // Set palette from targa colour table (8 bpp).
    if (header.pixel_depth == 8)
    {
        if (set_targa_palette ("..\\image\\frame1.tga") != SUCCESS)
        {
            finish ();
            printf ("Error reading targa file colour table information.\n");
            exit (0);
        } // if
    } // if

    // Wait for a key to start.
    getch ();

    // Setup engine for blits.
    wait_for_fifo (3);
    regw (DP_SRC, FRGD_SRC_BLIT);
    regw (SRC_CNTL, 0);
    regw (DST_CNTL, DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT);

    // Main draw loop.
    i = 0;
    frame = 0;
    while (i < (MODE_INFO.xres - width))
    {
        // Display old frame, update new frame.
        
        // Wait for start of vertical blank.
        while (!(regr (CRTC_INT_CNTL) & 0x00000001));

        // Wait for end of vertical blank.
        while (regr (CRTC_INT_CNTL) & 0x00000001);

        // Restore previous frame (if first frame has occurred already).
        if (i > 0)
        {
            blit (savex, savey, i-step, y_draw, width, height);
        } // if

        // Save current frame.
        blit (i, y_draw, savex, savey, width, height);

        // Update current frame.
        blit (points[frame].x, points[frame].y, i, y_draw, width, height);

        // Cycle through frames.
        i = i + step;
        frame = (frame + 1) % frames;
        if (kbhit ()) break;
    } // while

    // Wait for a carriage return.
    getch ();

    // Batch command to restore old mode.
    finish ();

    exit (0);                           // No errors.

} // main
