/********************************************************************************
 * Rage 128 Chapter 4 sample code                                               *
 *                                                                              *
 * scaleblt.c - This program uses the front end scaler to perform scaled        *
 *              bit blts.                                                       *
 *                                                                              *
 * Copyright (c) 1999 ATI Technologies Inc. All rights reserved.                *
 ********************************************************************************/
#include <stdio.h>
#include <i86.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include "..\util\regdef.h"
#include "..\util\defines.h"
#include "..\util\main.h"

void R128_ScaleBlt (WORD, WORD, WORD, WORD, WORD, WORD, WORD, WORD);

/****************************************************************************
 * Main Program to demonstrate scaled bit block transfers (blts)            *
 *  Function: An image is repeatedly blt'd over the screen, at random       *
 *            widths and heights.  The front end scaler is used to scale    *
 *            and interpolate the data.                                     *
 *    Inputs: Arguments for mode spatial and colour resolution              *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void main (int argc, char *argv[])
{
    _img_info IMG_INFO;
    WORD srcx, srcy, dstx, dsty, srcheight, srcwidth;
    WORD dstwidth, dstheight;

    R128_StartUp (argc, argv);

    if (R128_AdapterInfo.xres <= 320)
    {
        R128_ShutDown ();
        printf ("\nThis program requires a resolution of at least 400x300.");
        printf ("\nProgram terminated.");
        exit (1);
    }

    if (R128_AdapterInfo.bpp == 8 || R128_AdapterInfo.bpp == 24)
    {
        R128_ShutDown ();
        printf ("\nThis program does not operate at 8 or 24 bpp.");
        printf ("\nProgram terminated.");
        exit (1);
    }

    // Load image into offscreen memory, just off the visisible screen.
    srcx = 0;
    srcy = R128_AdapterInfo.yres;
    IMG_INFO = Load_Image (TRAJECTORY_RECTANGULAR, R128_GetBPPValue (R128_AdapterInfo.bpp),
                            srcx, srcy);
    srcwidth = IMG_INFO.width;
    srcheight = IMG_INFO.height;

    while (!kbhit ())
    {
        dstx = rand () % (R128_AdapterInfo.xres - 50);
        dsty = rand () % (R128_AdapterInfo.yres - 50);
        dstwidth = rand () % (R128_AdapterInfo.xres-dstx);
        dstheight = rand () % (R128_AdapterInfo.yres-dsty);
        R128_ScaleBlt (srcx, srcy, srcwidth, srcheight,
                       dstx, dsty, dstwidth, dstheight);
    }

    // get keypress
    getch ();

    // Shut down the accelerator, set the old mode.
    R128_ShutDown ();

    exit (0);                           // No errors.

} // main


/****************************************************************************
 * R128_ScaleBlt (WORD src_x, WORD src_y, WORD src_width, WORD src_height,  *
 *                WORD dst_x, WORD dst_y, WORD dst_width, WORD dst_height)  *
 *  Function: performs a scaled bit blt through the front end scaler        *
 *    Inputs: WORD src_x - X location of top left corner of source data     *
 *            WORD src_y - Y location of top left corner of source data     *
 *            WORD src_width - width of source data                         *
 *            WORD src_height - height of source data                       *
 *            WORD dst_x - X location of top left corner of destination     *
 *            WORD dst_y - Y location of top left corner of destination     *
 *            WORD dst_width - width of destination                         *
 *            WORD dst_height - height of destination                       *
 *   Outputs: NONE.                                                         *
 ****************************************************************************/
void R128_ScaleBlt (WORD src_x, WORD src_y, WORD src_width, WORD src_height,
                    WORD dst_x, WORD dst_y, WORD dst_width, WORD dst_height)
{
    DWORD save_tex_cntl, save_scale_3d_cntl, save_dp_datatype, save_dp_mix;
    DWORD temp;
    double factor = 65536.0;
    double scalef;

    // Save the control registers that will be modified.
    R128_WaitForFifo (4);
    save_tex_cntl = regr (TEX_CNTL);
    save_scale_3d_cntl = regr (SCALE_3D_CNTL);
    save_dp_datatype = regr (DP_DATATYPE);
    save_dp_mix = regr (DP_MIX);

    R128_WaitForFifo (18);

    // Set the mix to a source copy, with a rectangular source
    regw (DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT);
    temp = R128_GetBPPValue (R128_AdapterInfo.bpp);

    // set this to NO BRUSH!
    regw (DP_DATATYPE, temp | (15 << 8) | SRC_DSTCOLOR);

    // enable scaling with blending
    regw (SCALE_3D_CNTL, 0x00000040);

    // disable any texture features
    regw (TEX_CNTL, 0x00000000);
    regw (MISC_3D_STATE_CNTL_REG, 0x00000100);

    // Set up the front end scaler
    regw (SCALE_3D_DATATYPE, temp);
    regw (CLR_CMP_MASK_3D, 0xFFFFFFFF);
    regw (SCALE_SRC_HEIGHT_WIDTH, (src_height << 16) | src_width);

    // calculate the offset of the scaler data
    temp = R128_AdapterInfo.xres * src_y * R128_AdapterInfo.bytepp + src_x;
    regw (SCALE_OFFSET_0, temp);

    // set SCALE_PITCH
    // Because we've loaded the image into offscreen memory in a rectangular
    // trajectory, our scaler pitch will be equal to the screen pitch.
    regw (SCALE_PITCH, R128_AdapterInfo.pitch);

    // Disable any motion compensation features
    regw (MC_SRC1_CNTL, 0x00000000);

    scalef = (double)src_width/(double)dst_width;
    regw (SCALE_X_INC, (DWORD)(scalef * factor));

    scalef = (double)src_height/(double)dst_height;
    regw (SCALE_Y_INC, (DWORD)(scalef * factor));
    regw (SCALE_HACC, 0x00000000);
    regw (SCALE_VACC, 0x00000000);
    regw (SRC_Y_X, (src_y << 16) | src_x);
    regw (SCALE_DST_X_Y, (dst_x << 16) | dst_y);
    regw (SCALE_DST_HEIGHT_WIDTH, (dst_height << 16) | dst_width);

    // Now restore the registers we changed.
    R128_WaitForFifo (4);
    regw (TEX_CNTL, save_tex_cntl);
    regw (SCALE_3D_CNTL, save_scale_3d_cntl);
    regw (DP_DATATYPE, save_dp_datatype);
    regw (DP_MIX, save_dp_mix);

    return;
} // R128_ScaleBlt ()
