/******************************************************************************
 * mach64 Chapter 8 sample code                                               *
 *                                                                            *
 * fescaler.c - This program uses the GT engine to perform a blt using        *
 * the front end scaler to colour space convert the blt.  We will take a      *
 * YVYU source image, display it on the screen, and then blt it through       *
 * the front end scaler, converting it to RGB.                                *
 *                                                                            *
 * Copyright (c) 1994-1998 ATI Technologies Inc.  All rights reserved.        *
 ******************************************************************************/

#include <stdio.h>
#include "..\util\atim64.h"
#include "..\util\defines.h"
#include "..\util\definevt.h"
#include "..\util\atim64vt.h"
#include "..\util\main.h"

// Prototypes
void fes_blit (int x, int y, int dwidth, int dheight);

// Globals
unsigned long int INVERT = 0;

/******************************************************************************
 * Main Program to demonstrate front end scaler CSC usage                     *
 *  Function: A simple screen to screen bitblit is performed on a YUV image   *
 *            that is first loaded up onto the screen, then sent through      *
 *            front end scaler, colour space converted to RGB, then           *
 *            displayed on the screen. We do a second csc blt, this time      *                                       
 *            scaling the image down by half, then a 3rd blt inverted and     *
 *            scaled up to 125% of the size of the original image             *
 *    Inputs: Arguments for mode spatial and colour resolution                *
 *   Outputs: NONE                                                            *
 ******************************************************************************/
void main (int argc, char *argv[])
{
    int x1;                             // x coordinate of point 2.
    int y1;                             // y coordinate of point 2.
    unsigned long int temp;
    int iReturnValue;
    img_handle *ReturnPtr;
    int newdheight, newdwidth;
    float scalex, scaley;
    
    printf ("3D RAGE Chapter 8 sample code\n"
            "\n"
            "fescaler.c\n"
            "Spatial resolution (640, 800, 1024, 1280, 1600) and Colour Depth\n"
            "(16 or 32) should be passed as arguments.\n"
            "Default setting is 640x480 spatial resolution and 8bpp pixel depth.\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);
    }

    // check to make sure the proper hardware is installed to run the program
    // i.e. 3D RAGE II+ or 3D RAGE PRO
    if ( (!is_gtbplus()) && (!is_pro()) )
    {
        finish ();
        printf ("\nWarning: Unable to detect a 3D RAGE II+/C or 3D RAGE PRO!\n");
        printf ("Reminder: This program only works with a 3D RAGE II+/C or 3D RAGE PRO!\n");
        exit (1);
    }


    // Make sure we are in 16 or 32bpp mode.
    if ((MODE_INFO.bpp != 16) && (MODE_INFO.bpp != 32))
    {
        // Disable accelerator mode and switch back to VGA text mode.
        finish ();
        printf ("FESCALER requires a colour depth of 16 or 32bpp.\n");
        exit (1);
    } // if


    // Sample drawing routines.
    clear_screen (0, 0, MODE_INFO.xres, MODE_INFO.yres);

    // Load a test image into offscreen video memory.
    // This will be the front end scaler source.
    ReturnPtr = get_img_header ("..\\image\\testyvyu.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);
    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 (14);

    // Setup front end scaler for the blt
    // enable the front end scaler by setting the SCALE_3D_CNTL register
    regw (SCALE_3D_CNTL, 0x00000040);

    // set registers to a known state
    regw (ALPHA_TST_CNTL, 0x00000000);  // ensure that no alpha blending states are on
    regw (TEX_CNTL, 0x00000000); // ensure no lighting states are on

    // Set source buffer for front end scaler
    // This will point to the location where the image was loaded
    regw (SCALE_OFF, ( (MODE_INFO.yres) * MODE_INFO.xres * 
                                                (MODE_INFO.bpp/8) ) );

    regw (SCALE_PITCH, MODE_INFO.pitch * (MODE_INFO.bpp/16) );

    // Set front end scaler dimensions 
    regw (SCALE_WIDTH, 320);
    regw (SCALE_HEIGHT, 200);
    regw (SCALE_HACC, 0 );
    regw (SCALE_VACC, 0 );
    
    temp = regr (SCALE_X_INC);
    temp &= 0x0F; // preserve the reserved bits
    regw (SCALE_X_INC, (temp | (1 << 16)) );
    
    temp = regr (SCALE_Y_INC);
    temp &= 0x0F; // preserve the reserved bits
    regw (SCALE_Y_INC, (temp | (1 << 16)) );

    wait_for_fifo (5);
    // specify both fgrd and bgrd source coming from scaler
    regw (DP_SRC, 0x00000505 );  
    // set the approriate destination pix_width, based on display mode
    switch(MODE_INFO.bpp)
    {
        case 16:    if (is_gtb())
                    {
                        temp = 0xB2000B04;
                    }
                    else
                    {
                        temp = 0xC2000C04;
                    }
                    break;
        case 32:    if (is_gtb())
                    {
                        temp = 0xB2000B04;
                    }
                    else
                    {
                        temp = 0xC2000C06;
                    }
                    break;
        default:    break;
    }
     
    regw (DP_PIX_WIDTH, temp );
    regw (DP_WRITE_MSK, 0xFFFFFFFF );
    regw (DP_MIX, 0x00070007 );
    regw (GUI_TRAJ_CNTL, 0x00000003 );
    

    //    The source data is at (x1 y1) and has a size of (swidth, sheight).
    //    The destination of the blit will be drawn at (x2, y2).
    x1 = 0;
    y1 = 0;
    newdwidth = 320;
    newdheight = 200;
    
    // blt the image through the front end scaler
    fes_blit (x1, y1, newdwidth, newdheight);

    // Wait for key to be hit
    getch ();

    // repeat blt, but scale it down by one half
    scalex = 65536.0 * 2.0;
    scaley = 65536.0 * 2.0;

    newdwidth = 160; // new width, as we have scaled it down by half
    newdheight = 100; // new height, cut in half
    
    wait_for_fifo(6);

    temp = regr (SCALE_X_INC);
    temp &= 0x0F; // preserve the reserved bits
    temp = temp | (unsigned long) scalex;
    regw (SCALE_X_INC, temp);
    
    temp = regr (SCALE_Y_INC);
    temp &= 0x0F; // preserve the reserved bits
    temp = temp | (unsigned long) scaley;
    regw (SCALE_Y_INC, temp);

    // do the blt
    fes_blit ( (MODE_INFO.xres - newdwidth), 0, newdwidth, newdheight);
   
    // Wait for key to be hit
    getch ();

    // let's do another blt, inverted and scaled up 1.25 times

    scalex = 65536.0 * 0.8; // 0.8 is 1.25 inverted
    scaley = 65536.0 * 0.8;

    newdwidth = 400; // new width, as we have scaled it up by 25%
    newdheight = 250; // new height, with 25% increase
    
    wait_for_fifo(6);

    temp = regr (SCALE_X_INC);
    temp &= 0x0F; // preserve the reserved bits
    temp = temp | (unsigned long) scalex;
    regw (SCALE_X_INC, temp);
    
    temp = regr (SCALE_Y_INC);
    temp &= 0x0F; // preserve the reserved bits
    temp = temp | (unsigned long) scaley;
    regw (SCALE_Y_INC, temp);

    // set the GUI_TRAJ_CNTL to do a bottom to top blt (to invert the image)
    wait_for_fifo (1);
    regw (GUI_TRAJ_CNTL, 0x00000001 );

    INVERT = 1;
    
    fes_blit ( (MODE_INFO.xres - newdwidth), (MODE_INFO.yres - newdheight - 1), 
                            newdwidth, newdheight);

    INVERT = 0;
    
    // Wait for key to be hit
    getch ();
    
    // Batch command to restore old mode.
    finish ();
    
    exit (0);                           // No errors.

} // main


/******************************************************************************
 * fes_blit                                                                   *
 *  Function: Performs a blt using the front end scaler                       *
 *    Inputs: x - top left destination x coordinate in pixels                 *
 *            y - top left destination y coordinate in pixels                 *
 *            dwidth - width of destination blits block                       *
 *            dheight - height of destination block                           *
 *   Outputs: NONE                                                            *
 *     Notes: Blits the contents of front end scaler to the destination       *
 *            defined by x, y, with a size of dwidth and dheight.             *            This is known as an unbounded Y source trajectory blit. 
 ******************************************************************************/
void fes_blit (int x, int y, int dwidth, int dheight)
{

    // Perform a blit.
    wait_for_fifo (4);
    
    regw (DST_X, x);
    
    if(INVERT)
    {
        regw (DST_Y, y + dheight);
    }
    else
    {
        regw (DST_Y, y);
    }

    regw (DST_HEIGHT, dheight); // height of image
    regw (DST_WIDTH, dwidth); // width of image

    return;
    
} // fes_blit
