/******************************************************************************
 * mach64 Chapter 6 sample code                                               *
 *                                                                            *
 * slblit.c - This program uses the mach64 engine to perform a strictly       *
 * linear bitblit.  (source trajectory 4 - General Pattern)                   *
 *                                                                            *
 * 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"

/******************************************************************************
 * Main Program to demonstrate a strictly linear source bitblit               *
 *  Function: Draws a checkered pattern in linear memory at the top of        *
 *            of the screen.  This pattern is then blitted to the centre      *
 *            of the screen.                                                  *
 *    Inputs: Arguments for mode spatial and colour resolution                *
 *   Outputs: NONE                                                            *
 ******************************************************************************/

void main (int argc, char *argv[])
{
    char *pointer;                      // Virtual base of on screen memory.
    int width;                          // Width of work area.
    int height;                         // Height of work area.
    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.
    unsigned long rotation;             // Used for 24bpp rotation.
    int n = 4;                          // (n x n) # checkers in pattern.
    unsigned long col;                  // Colour value written to screen.
    int col1 = DARKBLUE;                // Checkered pattern first colour.
    int col2 = YELLOW;                  // Checkered pattern second colour.
    int coltemp;                        // Used when colours are switched.
    int count1;                         // Checkered row counter.
    int count2;                         // Pixel row counter.
    int count3;                         // Checkered column counter.
    int count;                          // Used for bpp greater than 8.

    printf ("mach64 Chapter 6 sample code\n"
            "\n"
            "slblit.c\n"
            "This program demonstrates a strictly linear bitblit.  First it draws\n"
            "a checkered pattern in linear memory at offset 0 (top left corner of\n"
            "the screen).  This pattern is then blitted using the strictly linear\n"
            "trajectory into a rectangle at the center of the screen.\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);

    // Get virtual address.
    pointer = (char *) MODE_INFO.virt_seg;

    // Setup dimensions of work area.
    width = 640;
    height = 480;

    // Destination rectangle size.
    dstwidth = width / 8;
    dstheight = height / 6;

    // Destination rectangle position is centered on screen.
    dstx = (MODE_INFO.xres - dstwidth) / 2;
    dsty = (MODE_INFO.yres - dstheight) / 2;

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

    // Use linear aperture to draw an n x n checkered pattern in memory as a
    // source.  Location is at start of on screen memory so you can see it.
    // traverse checkered rows.

    for (count1 = 0; count1 < n; count1++)
    {
        // Traverse rows.
        for (count2 = 0; count2 < (dstheight/n); count2++)
        {
            // Traverse checkered columns.
            for (count3 = 0; count3 < n; count3++)
            {
                // Fill memory with colour 1 for dstwidth/n pixels.
                col = get_colour_code (col1);
                switch (MODE_INFO.bpp)
                {
                    case 8:
                        memset (pointer, col, dstheight/n);
                        pointer += dstheight/n;
                        break;

                    case 15:
                    case 16:
                        for (count = 0; count < dstheight/n; count++)
                        {
                            *pointer = col;
                            *(pointer + 1) = col >> 8;
                            pointer += 2;
                        } // for
                        break;

                    case 24:
                        for (count = 0; count < dstheight/n; count++)
                        {
                            *pointer = col;
                            *(pointer+1) = col >> 8;
                            *(pointer+2) = col >> 16;
                            pointer += 3;
                        } // for
                        break;

                    case 32:
                        for (count = 0; count < dstheight/n; count++)
                        {
                            *pointer = col;
                            *(pointer+1) = col >> 8;
                            *(pointer+2) = col >> 16;
                            *(pointer+3) = col >> 24;
                            pointer += 4;
                        } // for
                        break;

                    default:
                        exit (0);
                } // switch

                // Switch col1 and col2.
                coltemp = col1;
                col1 = col2;
                col2 = coltemp;
            } // for
        } // for

        // Switch col1 and col2.
        coltemp = col1;
        col1 = col2;
        col2 = coltemp;
    } // for

    // End of pattern setup.

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

    // Perform a linear source bitblit:
    //    The source data is at base of linear aperture (SRC_OFFSET = 0).
    //    The destination blit will be drawn at (dstx, dsty) with the size
    //    of (dstwidth, dstheight).

    // 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 (7);
    regw (DP_SRC, MONO_SRC_ONE | FRGD_SRC_BLIT);

    // Use strictly linear for source:
    //    Using strictly linear source uses the available memory very
    //    effiecently.  No space is wasted since all of the information
    //    is packed together.  This can bee seen at the top of the screen.
    regw (SRC_CNTL, SRC_LINEAR_ENABLE);

    // 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
