/******************************************************************************
 * mach64 Chapter 6 sample code                                               *
 *                                                                            *
 * rect.c - This program uses the mach64 engine to draw rectangles.           *
 * The engine is initalized as in chapter 5.  Clear Screen and draw           *
 * Rectangle are the functions introduced here.  Clear Screen uses the        *
 * draw rectangle function but uses a different mixing technique.             *
 *                                                                            *
 * 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"

// Prototypes.

void draw_rect (int x, int y, int width, int height);
void clr_screen (int x, int y, int width, int height);

/******************************************************************************
 * Main Program to demonstrate rectangle drawing                              *
 *  Function: Demonstrates mach64 engine rectangle drawing feature.           *
 *            A matrix of n x n rectangles are drawn in a total area of       *
 *            width * height.  Colours are the base ega standard colours      *
 *            set up upon initializing the mode.                              *
 *    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 i;                              // Counter for rows of rectangles.
    int j;                              // Counter for columns of rectangles.
    int n;                              // # rectangles in x and y direction.
    int rcolour;                        // Colour of rectangle.
    int rx;                             // Top left x coordinate of rectangle.
    int ry;                             // Top left y coordinate of rectangle.
    int rwidth;                         // Width of rectangle.
    int rheight;                        // Height of rectangle.

    printf ("mach64 Chapter 6 sample code\n"
            "\n"
            "rect.c\n"
            "This program demonstrates the simple rectangle draw function of the\n"
            "mach64 engine.\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.
    n = 4;                              // > 0 ,<= min (width, height)

    // Sample drawing routines.
    clr_screen (0, 0, MODE_INFO.xres, MODE_INFO.yres);
    for (i = 0; i < n; i++)
    {
        for (j = 0; j < n; j++)
        {
            // Setup parameters.
            rcolour = (n*i + j)%NUM_COLOURS;
            rx = ((MODE_INFO.xres - width)/2) + (j*width/n);
            ry = ((MODE_INFO.yres - height)/2) + (i*height/n);
            rwidth = width/n;
            rheight = height/n;

            // Draw rectangle.
            wait_for_fifo (2);
            regw (DP_FRGD_CLR, get_colour_code (rcolour));
            regw (DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE);
            draw_rect (rx, ry, rwidth, rheight);
        } // for
    } // for
    
    // wait for carriage return
    getch ();

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

    exit (0);                           // No errors.

} // main


/******************************************************************************
 * draw_rect                                                                  *
 *  Function: uses the mach64 engine to draw a rectangle                      *
 *    Inputs: x - starting x coordinate in pixels (left most)                 *
 *            y - starting y coordinate in pixels (top most)                  *
 *            width - width of rectangle in pixels                            *
 *            height - height of rectangle in pixels                          *
 *   Outputs: NONE                                                            *
 ******************************************************************************/

void draw_rect (int x, int y, 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)
    {
        // Set 24 bpp alignment while maintaining direction bits. The
        // argument to this macro must be a 24bpp value.

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

        // Adjust horizontal parameters. Note that this adjustment is
        // performed AFTER calling the GET24BPPROTATION macro, as this
        // macro expects unadjusted 24 bpp values.

        x = x * 3;
        width = width * 3;

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

    // Perform rectangle fill.
    regw (DST_X, (unsigned long) x);
    regw (DST_Y, (unsigned long) y);
    regw (DST_HEIGHT, (unsigned long) height);
    regw (DST_WIDTH, (unsigned long) width);

    // Restore.
    regw (DST_CNTL, temp);

    return;

} // draw_rect


/******************************************************************************
 * clr_screen                                                                 *
 *  Function: uses the mach64 engine clear the screen.  The routine           *
 *            draw_rect is used, along with setting the mix to '0'.           *
 *    Inputs: x - starting x coordinate in pixels (left most) (0)             *
 *            y - starting y coordinate in pixels (top most)  (0)             *
 *            width - width of clear area in pixels           (xres)          *
 *            height - height of clear area in pixels         (yres)          *
 *   Outputs: NONE                                                            *
 *     Notes: values in brackets to clear entire screen                       *
 ******************************************************************************/

void clr_screen (int x, int y, int width, int height)
{
    unsigned long temp;

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

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

    // Perform clear screen.
    regw (DP_MIX, FRGD_MIX_ZERO | BKGD_MIX_ZERO);
    draw_rect (x, y, width, height);

    // Wait for clear screen operation to finish before exiting.
    wait_for_idle ();

    // Restore DP_MIX register.
    regw (DP_MIX, temp);

    return;

} // clr_screen
