/****************************************************************************
 * Rage 128 Chapter 7 sample code                                           *
 *                                                                          *
 * csc.c - This program uses the engine to perform colour space converted   *
 *         blts.                                                            *
 *                                                                          *
 * Copyright (c) 1999 ATI Technologies Inc. All rights reserved.            *
 ****************************************************************************/
#include <stdio.h>
#include <i86.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include "..\util\regdef.h"
#include "..\util\defines.h"
#include "..\util\main.h"

void R128_CSCBlt (BYTE, WORD, WORD, WORD, WORD, WORD, WORD, WORD, WORD);

/****************************************************************************
 * Main Program to demonstrate colour space converted bit block transfers   *
 *  Function: A test image is loaded in various source formats, and colour  *
 *            space converted to the current screen pixel depth.            *
 *    Inputs: Arguments for mode spatial and colour resolution              *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void main (int argc, char *argv[])
{
    BYTE test;
    _img_info img;
    WORD srcx, srcy, dstx, dsty, srcheight, srcwidth;
    WORD dstwidth, dstheight;
    BYTE img_fmt[] = { 3, 4, 6, 0xB, 0xC };
    char *format[] = { "15 bpp", "16 bpp", "32 bpp", "VYUY", "YVYU", NULL };
    char msg [80];
    char msg2 [80];
    int msgx, msgy;

    R128_StartUp (argc, argv);

    if (R128_AdapterInfo.bpp == 8)
    {
        R128_ShutDown ();
        printf ("\nCSC.EXE cannot be run in 8 bpp mode.");
        printf ("\nSelect a higher colour depth.");
        exit (1);
    }

    R128_LoadText ();
    sprintf (msg, "%d x %d: %d bpp", R128_AdapterInfo.xres, R128_AdapterInfo.yres,
                                     R128_AdapterInfo.bpp);
    test = strlen (msg);
    msgx = (R128_AdapterInfo.xres - (TEXT_INFO.actual_width * test))/2;
    msgy = (R128_AdapterInfo.yres - TEXT_INFO.height)/2;


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

    test = 0;
    srcx = 0;
    srcy = 0;

    R128_ClearScreen (LIGHTMAGENTA);
    R128_Delay (10);

    while (!kbhit ())
    //while (getch ()!=32)
    {
        R128_ClearScreen (LIGHTMAGENTA);
        img = Load_Image (TRAJECTORY_RECTANGULAR, (DWORD)img_fmt[test], srcx, srcy);
        srcwidth = img.width;
        srcheight = img.height;

        sprintf (msg2, "Source image: %s", format[test]);
        R128_PrintText (msg2, 10, R128_AdapterInfo.yres/4*3, BLACK, WHITE, 0);
        R128_PrintText (msg, msgx, msgy, BLACK, WHITE, 1);
        //R128_Delay (2);

        dstx = R128_AdapterInfo.xres - img.width;
        dsty = R128_AdapterInfo.yres - img.height;

        dstwidth = srcwidth;
        //fl = (float)srcheight * (float)img.bytepp/(float)R128_AdapterInfo.bytepp;
        dstheight = srcheight;
        R128_CSCBlt (img_fmt[test], srcx, srcy, srcwidth, srcheight,
                     dstx, dsty, dstwidth, dstheight);

        // increment and reset the counter if required.
        if (test++ >= 4) test = 0;

        R128_Delay (20);
    }

    // get keypress
    getch ();

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

    exit (0);                           // No errors.

} // main


/****************************************************************************
 * R128_CSCBlt (BYTE img_format, 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 colour space converted blt                         *
 *    Inputs: BYTE img_format - image format bits per pixel format          *
 *            WORD src_x - X location of source image in display memory     *
 *            WORD src_y - Y location of source image in display memory     *
 *            WORD src_width - width of source image, in pixels             *
 *            WORD src_height - height of source image, in pixels           *
 *            WORD dst_x - destination X location of converted image        *
 *            WORD dst_y - destination Y location of converted image        *
 *            WORD dst_width - width of destination image, in pixels        *
 *            WORD dst_height - height of destination image, in pixels      *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void R128_CSCBlt (BYTE img_format, 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;
    DWORD save_dp_mix;
    DWORD temp;
    double factor = 65536.0;
    double scalef;
    float f;
    WORD bytepp[] = { 0, 0, 1, 2, 2, 3, 4, 1, 1, 1, 2, 2, 2, 4, 2 };

    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_WaitForIdle ();

    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);
    // Disable any motion compensation features
    regw (MC_SRC1_CNTL, 0x00000000);

    // Set the scaler data format, as passed by img_format
    temp = regr (SCALE_3D_DATATYPE);
    temp &= ~(0x0000000F);
    temp |= img_format;
    regw (SCALE_3D_DATATYPE, temp);
    regw (CLR_CMP_MASK_3D, 0xFFFFFFFF);
    if (img_format == 5) src_width *= 3;
    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
    // This will equal the display pitch, as the image is loaded in a
    // rectangular trajectory
    f = (float)R128_AdapterInfo.pitch * ((float)R128_AdapterInfo.bytepp/(float)bytepp[img_format]);
    if (img_format == 5) f *= 3.0;
    regw (SCALE_PITCH, (DWORD)f);

    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_WaitForIdle ();
    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_CSCBlt ()

