/******************************************************************************
 * mach64 Chapter 8 sample code                                               *
 *                                                                            *
 * overlay.c - Program to demonstrate access to the VT specific registers.    *
 *                                                                            *
 * Copyright (c) 1994-1998 ATI Technologies Inc.  All rights reserved.        *
 ******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <i86.h>
#include "..\util\atim64vt.h"
#include "..\util\definevt.h"
#include "..\util\main.h"

// Prototypes.
void set_ovrly (int x, int y, int width, int height);

// Globals
int ISVTGT = 0, ISREVB = 0;


/******************************************************************************
 * Main Program to demonstrate access to VT specific registers to set up a    *
 * simple overlay.                                                            *
 *  Function: demonstrate VT register access by setting up a simple overlay.  *
 *    Inputs: Arguments for mode spatial and colour resolution                *
 *   Outputs: NONE                                                            *
 ******************************************************************************/

void main (int argc, char *argv[])
{
    int xcurr, ycurr, xdir, ydir;
    int iReturnValue;
    img_handle *ReturnPtr;
    
    printf ("\nmach64 Chapter 8 sample code\n"
            "\n"
            "overlay.c\n"
            "This program sets up a simple overlay using the mach64VT/GT\n"
            "\n"
            "This program is only available in 16bpp pixel depth.\n"
            "Spatial resolution (640, 800, 1024, 1280, 1600) should be passed 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.

    // Cases when program fails to set color depth and/or spatial resolution.
    // Program will terminate immediately and returns user to dos prompt.
    if (!(start (argc, argv)))
    {
        printf("\nPress any key to exit...\n");
        getch();
        finish();
        exit(1);
    }

    
    //  Detect for VT/GT.  Program will terminate if neither GT nor VT exists.
    ISVTGT = is_vtgt();

    if (!ISVTGT)
    {
        finish();
        printf("\nWarning: Unable to detect a VT or a GT!\n");
        printf("Reminder: This program only works with a VT or a GT!\n");
        exit(1);
    }

    //  Obtain asic revision information and handle accordingly.
    ISREVB = is_revb_or_greater();

    clear_screen (0, 0, MODE_INFO.xres, MODE_INFO.yres);

    // Make sure we are in 16bpp mode.

    if (MODE_INFO.bpp != 16)
    {
        // Disable accelerator mode and switch back to VGA text mode.
        finish ();
        printf ("OVERLAY requires colour depth of 16 bpp.\n");
        exit (1);
    } // if

    // Load a test image into the bottom left corner of the display.
    // This will be the overlay capture source.

    ReturnPtr = get_img_header ("..\\image\\test16.img");
    if (ReturnPtr == NULL)
    {
        // Disable accelerator mode and switch back to VGA text mode.
        finish ();
        printf ("Program was not able to read the image header.\n");
        exit (1);
    }

    iReturnValue = load_img (ReturnPtr, 0, MODE_INFO.yres - 200);
    if (iReturnValue == LOAD_FAILED)
    {
        // Disable accelerator mode and switch back to VGA text mode.
        finish ();
        printf ("Program was not able to load the image file.");
        exit (1);
    }

    // Free up memory used by pointer
    free(ReturnPtr);

    wait_for_fifo (6);

    // Setup overlay.
    regw (BUS_CNTL, regr (BUS_CNTL) | 0x08000000);  // Enable register block 1

    // Set the overlay scaler control and scaling values.
    regw (OVERLAY_SCALE_CNTL, SCALE_ZERO_EXTEND | SCALE_RED_TEMP_6500K |
                              SCALE_HORZ_BLEND | SCALE_VERT_BLEND);


    // Detect if a 3D RAGE PRO is installed, then set the co-efficient regs
    if(is_pro())
    {
        pro_overlay_init();
    }
    
    // Set input video format.
    regw (VIDEO_FORMAT, SCALE_IN_16BPP);

    // Set source buffer for capture.  Point to image.

    if (!ISREVB)
    {
        regw (BUF0_OFFSET, (MODE_INFO.yres - 200) * MODE_INFO.xres * 2);
    }
    else
    {
        regw (SCALER_BUF0_OFFSET, (MODE_INFO.yres - 200) * MODE_INFO.xres * 2);
    }

    if (!ISREVB)
    {
        regw (BUF0_PITCH, MODE_INFO.pitch);
    }
    else
    {
        regw (SCALER_BUF0_PITCH, MODE_INFO.pitch);
    }


    // Set scaler dimensions and capture configuration.
    regw (CAPTURE_CONFIG, SCALER_FRAME_READ_MODE_FULL |
                          SCALER_BUF_MODE_SINGLE | SCALER_BUF_NEXT_0);

    // Set overlay location (upper left corner of display) and mix key.
    set_ovrly (0, 0, 320, 200);
    if (MODE_INFO.xres>1024)
    {
        set_scale (320, 200, 320, 100);
    }
    else
    {
        set_scale (320, 200, 320, 200);
    }

    wait_for_fifo (2);

    if (!ISREVB)
    {
        regw (OVERLAY_KEY_CNTL, OVERLAY_MIX_ALWAYS_V | (OVERLAY_EXCLUSIVE_NORMAL<<28));
    }
    else
    {
        regw (OVERLAY_KEY_CNTL, 0x011);
    }


    // Enable the scaler/overlay.
    regw (OVERLAY_SCALE_CNTL, regr (OVERLAY_SCALE_CNTL) | OVERLAY_ENABLE |
                              SCALE_ENABLE);

    // Main draw loop.
    xcurr = 0;
    ycurr = 0;
    xdir = 1;
    ydir = 1;

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

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

        set_ovrly (xcurr, ycurr, 320, 200);

        xcurr += xdir;
        ycurr += ydir;

        if ((xcurr <= 0) || (xcurr >= MODE_INFO.xres - 321))
        {
            xdir = -xdir;
        } // if

        if ((ycurr <= 0) || (ycurr >= MODE_INFO.yres - 201))
        {
            ydir = -ydir;
        } // if

    } // while

    // Wait for a key press
    getch ();

    // Disable the scaler/overlay.
    wait_for_fifo (2);

    regw (OVERLAY_SCALE_CNTL, regr (OVERLAY_SCALE_CNTL) & ~OVERLAY_ENABLE &
                              ~SCALE_ENABLE);
    regw (BUS_CNTL, regr (BUS_CNTL) & 0xF7FFFFFF);  // Disable register block 1

    // Batch command to restore old mode.
    finish ();
    
    exit (0);                           // No errors.
} // main


/******************************************************************************
 * set_ovrly                                                                  *
 *  Function: uses the ATI264VT to set the overlay window.                    *
 *            The overlay window is placed at (x, y) of size (width x         *
 *            height) using the current settings.  For modes that use         *
 *            double-scan (typically low resolution modes like 320x200        *
 *            or 320x240) both the y-coordinate and the height must be        *
 *            multiplied by 2 to compensate for the double-scan.              *
 *    Inputs: x - starting x coordinate in pixels (left most)                 *
 *            y - starting y coordinate in pixels (top most)                  *
 *            width - width of overlay window in pixels                       *
 *            height - height of overlay window in pixels                     *
 *   Outputs: NONE                                                            *
 ******************************************************************************/

void set_ovrly (int x, int y, int width, int height)
{
    // If we're in a double-scan mode, double the y and height values.
    // Note: CRTC_GEN_CNTL is non-FIFOed, so wait_for_idle () not needed.

    if (regr (CRTC_GEN_CNTL) & 0x00000001)
    {
        y *= 2;
        height *= 2;
    } // if

    wait_for_fifo (2);

    regw (OVERLAY_Y_X, (x << 16) + y);
    regw (OVERLAY_Y_X_END, ((x + width) << 16) + y + height);

    return;
} // set_ovrly
