/******************************************************************************
 * mach64 Chapter 8 sample code                                               *
 *                                                                            *
 * scaler.c - Program to demonstrate access to the VT/3D RAGE 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"


#define TRUE            1
#define FALSE           0

// Prototypes.

void set_scaler (int src_width, int src_height, int dst_width, int dst_height);



/******************************************************************************
 * 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;

    unsigned int ISVTGT = 0, ISREVB = 0;

    img_handle *ReturnPtr;

    printf ("\nmach64 Chapter 8 sample code\n"
            "\n"
            "scaler.c\n"
            "This program demonstrates the scaler on 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 == 0)
    {
        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);
    }


    // call function to see if revB is installed, set ISREVB 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.\n");
        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);

    // Set input video format.
    regw (VIDEO_FORMAT, SCALE_IN_16BPP);
    
    // Set source buffer for capture.  Point to image.
    if (ISREVB==0)
    {
        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==0)
    {
        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);

    // Determine if 3D RAGE PRO is installed, and set co-efficient regs
    if(is_pro())
    {
        pro_overlay_init();
    }
    
    // Set overlay location (upper left corner of display) and mix key.
    set_overlay (0, 0, 320, 200);
    if (MODE_INFO.xres>1024)
    {
        set_scaler (320, 200, 320, 100);
    }
    else
    {
        set_scaler (320, 200, 320, 200);
    }

    wait_for_fifo (2);

    if (ISREVB==0)
    {
        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 = 320;
    ycurr = 200;
    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_overlay (0, 0, xcurr, ycurr);
        if (MODE_INFO.xres>1024)
        {
            set_scaler (320, 200, xcurr, ycurr/2);
        }
        else
        {
            set_scaler (320, 200, xcurr, ycurr);
        }

        xcurr += xdir;
        ycurr += ydir;

        if ((xcurr < ((abs(xdir)) * 2) ) || (xcurr >= MODE_INFO.xres - 1))
        {
            xdir = -xdir;
        } // if
        if ((ycurr < ((abs(ydir)) * 2) ) || (ycurr >= MODE_INFO.yres - 1))
        {
            ydir = -ydir;
        } // if
    } // while

    // Wait for a carriage return.
    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_scaler                                                                 *
 *  Function: uses the VT/3D RAGE to set the scaler size.                     *
 *            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_scaler (int src_width, int src_height, int dst_width, int dst_height)
{
    long h_inc, v_inc;

    // If a double-scan mode, double the destination height value.
    // Note: CRTC_GEN_CNTL is non-FIFOed, so wait_for_idle () not needed.

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

    // Compute horizontal and vertical scaling values in
    // fixed point 4.12 binary format.

    h_inc = (src_width << 12) / dst_width;
    v_inc = (src_height << 12) / dst_height;

    wait_for_fifo (2);

    regw (OVERLAY_SCALE_INC, (h_inc << 16) + v_inc);
    regw (SCALER_HEIGHT_WIDTH, (src_width << 16) + src_height);

    return;

} // set_scaler

