/******************************************************************************
 * mach64 Chapter 6 sample code                                               *
 *                                                                            *
 * sblit.c - This program uses the mach64 engine to perform a simple          *
 * 1 to 1 bitblit.  (unbounded y source, rectangle dest)                      *
 *                                                                            *
 * Copyright (c) 1994-1998 ATI Technologies Inc.  All rights reserved.        *
 ******************************************************************************/

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

// Prototypes.

void s_blit (int x1, int y1, int x2, int y2, int width, int height);

/******************************************************************************
 * Main Program to demonstrate simple 1 to 1 bitblits                         *
 *  Function: A simple screen to screen bitblit is performed on a simple      *
 *            draw pattern.  Two concentric rectangles are drawn in the       *
 *            top left quadrant of the screen.  The DP_SRC is set to a        *
 *            blit source (and mono source set to always '1').  Then the      *
 *            drawn rectangle are blitted to the bottom right quadrant.       *
 *    Inputs: Arguments for mode spatial and colour resolution                *
 *   Outputs: NONE                                                            *
 ******************************************************************************/

void main (int argc, char *argv[])
{
    int width;                          // Width of drawing area.
    int height;                         // Height of drawing area.
    int x1;                             // x coordinate of point 1.
    int y1;                             // y coordinate of point 1.
    int x2;                             // x coordinate of point 2.
    int y2;                             // y coordinate of point 2.
    int swidth;                         // Width of rectangle or blit.
    int sheight;                        // Height of rectangle or blit.

    printf ("mach64 Chapter 6 sample code\n"
            "\n"
            "sblit.c\n"
            "This program demonstrates a simple 1 to 1 screen bitblit.\n"
            "A simple screen to screen bitblit is performed on a simple draw\n"
            "pattern.  Two concentric rectangles are drawn in the top left quadrant\n"
            "of the screen.  The DP_SRC is set to a blit source (and mono source\n"
            "set to always '1').  Then the drawn rectangle are blitted to the\n"
            "bottom right quadrant.\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);

    // Set up values.
    width = 640;                        // Less than or equal to xres
    height = 480;                       // Less than or equal to yres

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

    // Draw light blue rectangle.
    wait_for_fifo (1);
    regw (DP_FRGD_CLR, get_colour_code (LIGHTBLUE));
    x1 = (MODE_INFO.xres - width)/2;
    y1 = (MODE_INFO.yres - height)/2;
    swidth = width/4;
    sheight = height/4;
    draw_rectangle (x1, y1, swidth, sheight);

    // Draw slightly smaller light magenta rectangle.
    wait_for_fifo (1);
    regw (DP_FRGD_CLR, get_colour_code (LIGHTMAGENTA));
    x1 = ((MODE_INFO.xres - width)/2) + width/32;
    y1 = ((MODE_INFO.yres - height)/2) + height/32;
    swidth = 3*width/16;
    sheight = 3*height/16;
    draw_rectangle (x1, y1, swidth, sheight);

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

    // Setup for simple one-to-one 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 (1);
    regw (DP_SRC, MONO_SRC_ONE | FRGD_SRC_BLIT);

    // Perform a simple one-to-one colour blit:
    //    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 = (MODE_INFO.xres - width)/2;
    y1 = (MODE_INFO.yres - height)/2;
    x2 = ((MODE_INFO.xres - width)/2) + (3*width/4);
    y2 = ((MODE_INFO.yres - height)/2) + (3*height/4);
    swidth = width/4;
    sheight = height /4;
    s_blit (x1, y1, x2, y2, swidth, sheight);

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

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

    exit (0);                           // No errors.

} // main


/******************************************************************************
 * s_blit                                                                     *
 *  Function: Performs a simple screen to screen blit                         *
 *    Inputs: x1 - top left source x coordinate in pixels                     *
 *            y1 - top left source y coordinate in pixels                     *
 *            x2 - top left destination x coordinate in pixels                *
 *            y2 - top left destination y coordinate in pixels                *
 *            width - width of blits block                                    *
 *            height - height of blits block                                  *
 *   Outputs: NONE                                                            *
 *     Notes: Copy the contents of screen memory at (x1, y1) of size          *
 *            (width x height) to (x2, y2) using the current engine           *
 *            settings. This is known as an unbounded Y source                *
 *            trajectory blit. For 24 bpp modes, the engine is in 8 bpp       *
 *            and the CRTC is in 24 bpp. For this reason, all horizontal      *
 *            parameters must be mulitplied by 3. The blit source is          *
 *            determined by the current setting of the DP_SRC register.       *
 ******************************************************************************/

void s_blit (int x1, int y1, int x2, int y2, int width, int height)
{
    unsigned long temp, rotation;

    // Wait for idle before reading GUI registers.
    wait_for_idle ();

    // Save used registers.
    temp = regr (DST_CNTL);

    if (MODE_INFO.bpp == 24)
    {
        // Get 24 bpp alignment rotation for destination.

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

        // Adjust horizontal parameters.

        x1 = x1 * 3;
        x2 = x2 * 3;
        width = width * 3;

        // Set 24 bpp alignment while maintaining direction bits.

        regw (DST_CNTL, (temp & 0xDF) | DST_24_ROTATION_ENABLE |
                        (rotation << 8));
    }

    // Perform a blit.
    regw (SRC_X, x1);
    regw (SRC_Y, y1);
    regw (SRC_HEIGHT1, height);
    regw (SRC_WIDTH1, width);

    regw (DST_X, x2);
    regw (DST_Y, y2);
    regw (DST_HEIGHT, height);
    regw (DST_WIDTH, width);

    // Restore.
    regw (DST_CNTL, temp);

    return;

} // s_blit
