/******************************************************************************
 * drawprim.c - Rage 128 drawing function code                                *
 *                                                                            *
 * This module contains the following functions:                              *
 *     void R128_ClearScreen (DWORD colour)                                   *
 *     void R128_DrawRectangle (DWORD x, DWORD y, DWORD width,                *
 *                              DWORD height, DWORD colour)                   *
 *                                                                            *
 * Copyright (c) 1999 ATI Technologies Inc.  All rights reserved.             *
 ******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include "defines.h"
#include "main.h"
#include "regdef.h"


/******************************************************************************
 * R128_ClearScreen (DWORD colour)                                            *
 *  Function: uses the accelerator to clear the screen.                       *
 *    Inputs: DWORD colour - new screen colour                                *
 *   Outputs: NONE.                                                           *
 ******************************************************************************/
void R128_ClearScreen (DWORD colour)
{
    R128_DrawRectangle (0, 0, R128_AdapterInfo.xres, R128_AdapterInfo.yres,
                        colour);
    return;

} // R128_ClearScreen

/******************************************************************************
 * R128_DrawRectangle (DWORD x, DWORD y, DWORD width, DWORD height,           *
 *                     DWORD colour)                                          *
 *  Function: performs a rectangle colour fill using the engine.              *
 *    Inputs: DWORD x - X location of top left corner of rectangle            *
 *            DWORD y - Y location of top left corner of rectangle            *
 *            DWORD width - width of rectangle                                *
 *            DWORD height = height of rectangle                              *
 *            DWORD colour - colour of rectangle                              *
 *   Outputs: NONE.                                                           *
 ******************************************************************************/
void R128_DrawRectangle (DWORD x, DWORD y, DWORD width, DWORD height,
                         DWORD colour)
{
    DWORD save_dp_datatype, bppvalue;

    R128_WaitForFifo (6);

    // Save the current DP_DATATYPE register value
    save_dp_datatype = regr (DP_DATATYPE);

    bppvalue = R128_GetBPPValue (R128_AdapterInfo.bpp);
    regw (DP_DATATYPE, (bppvalue | BRUSH_SOLIDCOLOR | ROP3_SRCCOPY));
    regw (DP_BRUSH_FRGD_CLR, R128_GetColourCode (colour));
    regw (DST_Y_X, (y << 16) | x);
    regw (DST_WIDTH_HEIGHT, (width << 16) | height);

    // restore the DP_DATATYPE register
    regw (DP_DATATYPE, save_dp_datatype);

    return;
} // R128_DrawRectangle


/******************************************************************************
 * R128_DrawLine (DWORD x1, DWORD y1, DWORD x2, DWORD y2, DWORD colour)       *
 *                                                                            *
 *  Function: draws a bresenham line using the engine                         *
 *    Inputs: DWORD x1 - starting X location of line                          *
 *            DWORD y1 - starting Y location of line                          *
 *            DWORD x2 - ending X location of line                            *
 *            DWORD y2 - ending Y location of line                            *
 *            DWORD colour - colour of rectangle                              *
 *   Outputs: NONE.                                                           *
 ******************************************************************************/
void R128_DrawLine (WORD x1, WORD y1, WORD x2, WORD y2, DWORD colour)
{
    int dx, dy;
    int small, large;
    int x_dir, y_dir, y_major;
    int err, inc, dec;
    DWORD save_dp_cntl, save_dp_datatype, bppvalue;

    // Determine x & y deltas and x & y direction bits.
    if (x1 < x2)
    {
        dx = x2 - x1;
        x_dir = 1 << 31;
    }
    else
    {
        dx = x1 - x2;
        x_dir = 0 << 31;
    } // if

    if (y1 < y2)
    {
        dy = y2 - y1;
        y_dir = 1 << 15;
    }
    else
    {
        dy = y1 - y2;
        y_dir = 0 << 15;
    } // if

    // Determine x & y min and max values; also determine y major bit.
    if (dx < dy)
    {
        small = dx;
        large = dy;
        y_major = 1 << 2;
    }
    else
    {
        small = dy;
        large = dx;
        y_major = 0 << 2;
    } // if

    // Calculate Bresenham parameters and draw line.
    err = (DWORD) (-large);
    inc = (DWORD) (2 * small);
    dec = (DWORD) (-2 * large);

    R128_WaitForFifo (11);

    save_dp_cntl = regr (DP_CNTL);
    save_dp_datatype = regr (DP_DATATYPE);

    // Set DP_DATATYPE
    bppvalue = R128_GetBPPValue (R128_AdapterInfo.bpp);
    regw (DP_DATATYPE, (bppvalue | BRUSH_SOLIDCOLOR | ROP3_SRCCOPY));

    // Draw Bresenham line.
    regw (DP_BRUSH_FRGD_CLR, R128_GetColourCode(colour));
    regw (DST_Y_X, (y1 << 16) | x1);

    // Allow setting of last pel bit and polygon outline bit for line drawing.
    regw (DP_CNTL_XDIR_YDIR_YMAJOR, (y_major | y_dir | x_dir));
    regw (DST_BRES_ERR, err);
    regw (DST_BRES_INC, inc);
    regw (DST_BRES_DEC, dec);
    regw (DST_BRES_LNTH, (DWORD) (large + 1));
    regw (DP_CNTL, save_dp_cntl);
    regw (DP_DATATYPE, save_dp_datatype);

    return;

} // R128_DrawLine ()


/******************************************************************************
 * R128_DrawBorder (DWORD colour)                                             *
 *                                                                            *
 *  Function: draws a coloured border on the screen by calling the            *
 *            R128_DrawBox function.                                          *
 *    Inputs: DWORD colour - colour of border                                 *
 *   Outputs: NONE.                                                           *
 ******************************************************************************/
void R128_DrawBorder (DWORD colour)
{
    R128_DrawBox (0, 0, R128_AdapterInfo.xres-1, R128_AdapterInfo.yres-1, colour);
}


/******************************************************************************
 * R128_DrawBox (WORD x, WORD y, WORD width, WORD height, DWORD colour)       *
 *                                                                            *
 *  Function: draws a box on the screen by calling the R128_DrawLine ()       *
 *            with the appropriate co-ordinates.                              *
 *    Inputs: WORD x - X location of top left corner of box                   *
 *            WORD y - Y location of top left corner of box                   *
 *            WORD width - width of box                                       *
 *            WORD height - height of box                                     *
 *            DWORD colour - colour of box                                    *
 *   Outputs: NONE.                                                           *
 ******************************************************************************/
void R128_DrawBox (WORD x, WORD y, WORD width, WORD height, DWORD colour)
{
     R128_DrawLine (x, y, x+width, y, colour); // top line
     R128_DrawLine (x+width, y, x+width, y+height, colour); // right side line
     R128_DrawLine (x, y, x, y+height, colour); // left side line
     R128_DrawLine (x, y+height, x+width, y+height, colour);
}


/******************************************************************************
 * R128_DrawPatternLine (WORD x1, WORD y1, WORD x2, WORD y2,                  *
 *                       DWORD brushtype, DWORD *data)                        *
 *                                                                            *
 *  Function: draws a patterned line using the engine                         *
 *    Inputs: DWORD x1 - starting X location of line                          *
 *            DWORD y1 - starting Y location of line                          *
 *            DWORD x2 - ending X location of line                            *
 *            DWORD y2 - ending Y location of line                            *
 *            DWORD brushtype - defines the type of brush used for the line   *
 *            DWORD *data = pointer to brush register data                    *
 *   Outputs: NONE.                                                           *
 ******************************************************************************/
void R128_DrawPatternLine (WORD x1, WORD y1, WORD x2, WORD y2,
                            DWORD brushtype, DWORD *data)
{
    int dx, dy;
    int small, large;
    int x_dir, y_dir, y_major;
    int err, inc, dec;
    DWORD save_dp_cntl, save_dp_datatype, bppvalue;

    R128_LoadPatternData (brushtype, data);

    // Determine x & y deltas and x & y direction bits.
    if (x1 < x2)
    {
        dx = x2 - x1;
        x_dir = 1 << 31;
    }
    else
    {
        dx = x1 - x2;
        x_dir = 0 << 31;
    } // if

    if (y1 < y2)
    {
        dy = y2 - y1;
        y_dir = 1 << 15;
    }
    else
    {
        dy = y1 - y2;
        y_dir = 0 << 15;
    } // if

    // Determine x & y min and max values; also determine y major bit.
    if (dx < dy)
    {
        small = dx;
        large = dy;
        y_major = 1 << 2;
    }
    else
    {
        small = dy;
        large = dx;
        y_major = 0 << 2;
    } // if

    // Calculate Bresenham parameters and draw line.
    err = (DWORD) (-large);
    inc = (DWORD) (2 * small);
    dec = (DWORD) (-2 * large);

    R128_WaitForFifo (11);

    save_dp_cntl = regr (DP_CNTL);
    save_dp_datatype = regr (DP_DATATYPE);

    // Set DP_DATATYPE
    bppvalue = R128_GetBPPValue (R128_AdapterInfo.bpp);
    regw (DP_DATATYPE, (bppvalue | brushtype | ROP3_PATCOPY));

    // Draw Bresenham line.
    regw (DST_Y_X, (y1 << 16) | x1);

    // Allow setting of last pel bit and polygon outline bit for line drawing.
    regw (DP_CNTL_XDIR_YDIR_YMAJOR, (y_major | y_dir | x_dir));
    regw (DST_BRES_ERR, err);
    regw (DST_BRES_INC, inc);
    regw (DST_BRES_DEC, dec);
    regw (DST_BRES_LNTH, (DWORD) (large + 1));
    regw (DP_CNTL, save_dp_cntl);
    regw (DP_DATATYPE, save_dp_datatype);

    return;

} // R128_DrawPatternLine ()


/******************************************************************************
 * R128_LoadPatternData (DWORD brushtype, DWORD *data)                        *
 *                                                                            *
 *  Function: loads the brush data registers with the supplied data           *
 *    Inputs: DWORD brushtype - defines the type of brush used for the line   *
 *            DWORD *data = pointer to brush register data                    *
 *   Outputs: NONE.                                                           *
 ******************************************************************************/
void R128_LoadPatternData (DWORD brushtype, DWORD *data)
{
    int i;
    WORD offset;

    /* this structure contains the number of dwords each brush type requires */
    WORD num_dwords[] = { 2, 2, 1, 1, 1, 1, 1, 1, 32, 32, 64, 8, 8 };

    R128_WaitForFifo (num_dwords[(brushtype >> 8)]);

    for (i = 0; i < num_dwords[(brushtype >> 8)]; i++)
    {
        offset = BRUSH_DATA0 + (i * 4);
        regw (offset, data[i]);
    }
    return;
}

