/******************************************************************************
 * mach64 Chapter 6 sample code                                               *
 *                                                                            *
 * gprblit.c - This program uses the mach64 engine to perform a general       *
 * pattern bitblit with rotation (source trajectory 4 - Gen Pat with Rot)     *
 *                                                                            *
 * Copyright (c) 1994-1998 ATI Technologies Inc.  All rights reserved.        *
 ******************************************************************************/

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

/******************************************************************************
 * Main Program to show a simple general pattern with rotation bitblit.       *
 *  Function: A general pattern (concentric coloured rectangles) is           *
 *            dranw in the top left corner of the screen.  This pattern       *
 *            is used to fill a blit area which is larger than the source.    *
 *            However, instead of starting at offset (0,0), the start is      *
 *            rotated to begin in the centre of the pattern.                  *
 *    Inputs: Arguments for mode spatial and colour resolution                *
 *   Outputs: NONE                                                            *
 ******************************************************************************/

void main (int argc, char *argv[])
{
    int width;                          // Width of work area.
    int height;                         // Height of work area.
    int srcx;                           // Top left x co-ord of source pattern.
    int srcy;                           // Top left y co-ord of source pattern.
    int srcwidth;                       // Width of source pattern.
    int srcheight;                      // Height of source pattern.
    int dstx;                           // Top left x co-ord of dest area.
    int dsty;                           // Top left y co-ord of dest area.
    int dstwidth;                       // Width of destination area.
    int dstheight;                      // Height of destination area.
    int src_xoffset;                    // Rotation x offset from srcx (right).
    int src_yoffset;                    // Rotation y offset from srcy (down).
    unsigned long rotation;             // Used for 24bpp rotation.

    printf ("mach64 Chapter 6 sample code\n"
            "\n"
            "gprblit.c\n"
            "This program demonstrates a general pattern bitblits with rotation.\n"
            "A general pattern (concentric coloured rectangles) is drawn in the top\n"
            "left corner of the screen.  This pattern is used to fill a blit area\n"
            "which is larger than the source.  However, instead of starting at\n"
            "(0,0), the start is rotated to begin in the centre of the pattern.\n"
            "\n"
            "Spatial resolution (640, 800, 1024, 1280, 1600) and Colour Depth\n"
            "(8, 15, 16, 24, 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.

    start (argc, argv);

    // Setup dimensions of source and destination.
    width = 640;
    height = 480;

    // Main source rectangle (source pattern).
    srcx = width / 32;
    srcy = height / 64;
    srcwidth = width / 16;
    srcheight = height / 12;

    // Destination rectangle.
    dstx = width / 8;
    dsty = height / 16;
    dstwidth = MODE_INFO.xres / 4;
    dstheight = MODE_INFO.yres / 3;

    // x and y offset from the top left corner of main source pattern.
    src_xoffset = srcwidth / 2;
    src_yoffset = srcheight / 2;

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

    // Draw some filled rectangles to act as a source.
    wait_for_fifo (1);
    regw (DP_FRGD_CLR, get_colour_code (WHITE));
    draw_rectangle (srcx, srcy, srcwidth, srcheight);

    wait_for_fifo (1);
    regw (DP_FRGD_CLR, get_colour_code (LIGHTBLUE));
    draw_rectangle (srcx + (width / 160), srcy + (height / 120),
                    srcwidth - (2 * (width / 160)),
                    srcheight - (2 * (height / 120)));

    wait_for_fifo (1);
    regw (DP_FRGD_CLR, get_colour_code (LIGHTGREEN));
    draw_rectangle (srcx + (2 * (width / 160)), srcy + (2 * (height / 120)),
                    srcwidth - (4 * (width / 160)),
                    srcheight - (4 * (height / 120)));

    wait_for_fifo (1);
    regw (DP_FRGD_CLR, get_colour_code (LIGHTRED));
    draw_rectangle (srcx + (3 * (width / 160)), srcy + (3 * (height / 120)),
                    srcwidth - (6 * (width / 160)),
                    srcheight - (6 * (height / 120)));

    // Wait for a carriage return (show screen before operation).
    getch ();

    // Perform a general pattern blit with rotation:
    //    The source data is at (srcx, srcy) and has a size of
    //    (srcwidth, srcheight). The destination blit will be drawn at
    //    (dstx, dsty) with a size of (dstwidth, dstheight). The gen pat
    //    rotation blit allows the source to wrap in the X & Y directions
    //    while continuing to draw to the destination.  The source rotation
    //    offset id (src_xoffset, src_yoffset).

    // Setup for colour blit:
    //    The monochrome path controls which source channel is used to read
    //    the source data. If the monochrome path is "1", the foreground
    //    channel is selected as the source; if the monochrome path is "0",
    //    the background channel is selected. In this case, the monochrome
    //    path will be set to "1".

    wait_for_fifo (11);
    regw (DP_SRC, MONO_SRC_ONE | FRGD_SRC_BLIT);

    // Use general pattern with rotation for source:
    //    This implies that the destination rectangle can be a different
    //    size than the source rectangle - in this example, the destination
    //    rectangle is larger.
    regw (SRC_CNTL, SRC_ROTATION_ENABLE | SRC_PATTERN_ENABLE);
    
    // Set source start coordinate and rectangle size.

    // Adjust source trajectory starting x value and width for 24 bpp mode.
    if (MODE_INFO.bpp == 24)
    {
        srcx = srcx * 3;
        srcwidth = srcwidth * 3;
        src_xoffset = src_xoffset * 3;
    } // if
    regw (SRC_X_START, srcx);
    regw (SRC_Y_START, srcy);
    regw (SRC_WIDTH2, srcwidth);
    regw (SRC_HEIGHT2, srcheight);
    regw (SRC_X, srcx + src_xoffset);
    regw (SRC_Y, srcy + src_yoffset);
    regw (SRC_WIDTH1, srcwidth - src_xoffset);
    regw (SRC_HEIGHT1, srcheight - src_yoffset);

    // Set draw direction bits and adjust for 24 bpp mode if required.
    if (MODE_INFO.bpp == 24)
    {
        // Get the dstx parameter 24bpp rotation before adjusting it.

        rotation = (unsigned long)(((dstx * 3) / 4) % 6);

        // Adjust horizontal parameters for 24 bpp.

        dstx = dstx * 3;
        dstwidth = dstwidth * 3;

        // Setup 24 bpp alignment.

        regw(DST_CNTL, DST_24_ROTATION_ENABLE | DST_Y_TOP_TO_BOTTOM |
                       DST_X_LEFT_TO_RIGHT | (rotation << 8));
    }
    else
    {
        regw (DST_CNTL, DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT);
    } // if

    // Set destination start coordinate and rectangle size.
    regw (DST_X, dstx);
    regw (DST_Y, dsty);
    regw (DST_HEIGHT, dstheight);
    regw (DST_WIDTH, dstwidth);         // This write initiates the operation.

    // Wait for a carriage return.
    getch ();

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

    exit (0);                           // No errors.

} // main
