/******************************************************************************
 * text.c - Rage 128 text drawing functions                                   *
 *                                                                            *
 * This module contains functions for loading and printing text using the     *
 * Rage 128 hardware.  The brush data registers are loaded with the character *
 * data, and a pattern blt is performed.                                      *
 *                                                                            *
 * Copyright (c) 1999 ATI Technologies Inc. All rights reserved.              *
 ******************************************************************************/
#include <stdio.h>
#include <i86.h>
#include <string.h>
#include <ctype.h>
#include "regdef.h"
#include "defines.h"
#include "main.h"

static BYTE text_data[9984];
_TEXT_INFO TEXT_INFO;

// special characters
DWORD colon32[32] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x38000000,
0x38000000, 0x38000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x38000000, 0x38000000,
0x38000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000
};

DWORD colon16[32] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000600, 0x00000600, 0x00000000, 0x00000000,
0x00000600, 0x00000600, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000
};

/****************************************************************************
 * R128_LoadText (void)                                                     *
 *  Function: Loads the appropriate data for the required font,             *
 *            also sets the appropriate global variable values.             *
 *    Inputs: NONE                                                          *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void R128_LoadText (void)
{
    FILE *file;
    WORD size;
    char filename[80];

    // determine the font we will use based on screen resolution
    // i.e. if we are using 1024 or higher, use 32x32 font, otherwise
    // use 16x16
    if (R128_AdapterInfo.xres >= 1024)
    {
        TEXT_INFO.height = 32;
        TEXT_INFO.width = 32;
        TEXT_INFO.actual_width = 18;
        strcpy (filename, "..\\..\\image\\csn32x32.icn");
        size = 2496;
    }
    else
    {
        TEXT_INFO.height = 16;
        TEXT_INFO.width = 16;
        TEXT_INFO.actual_width = 9;
        strcpy (filename, "..\\..\\image\\csn16x16.icn");
        size = 624;
    }

    file = fopen (filename, "r");
    fread (&text_data, sizeof(DWORD), size, file);
    fclose (file);

    return;
} // R128_LoadText ()


/****************************************************************************
 * R128_PrintText (char *data, WORD x, WORD y, DWORD foreground,            *
 *                 DWORD background, BYTE transparent)                      *
 *  Function: prints text to the screen.                                    *
 *    Inputs: char *data - the string to be printed                         *
 *            WORD x - X location where the string will be printed          *
 *            WORD y - Y location where the string will be printed          *
 *            DWORD foreground - foreground colour of the text              *
 *            DWORD background - background colour of the text              *
 *            BYTE transparent - (0) - use background colour                *
 *                               (1) - leave background alone               *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void R128_PrintText (char *data, WORD x, WORD y, DWORD foreground,
                    DWORD background, BYTE transparent)
{
    WORD length, loop;
    DWORD save_dp_datatype, bppvalue, brush, save_clr_cmp_cntl;
    DWORD save_scale_3d_cntl, save_tex_cntl, save_dp_mix;

    // save DP_DATATYPE and restore it later
    R128_WaitForIdle ();
    save_dp_datatype = regr (DP_DATATYPE);
    save_dp_mix = regr (DP_MIX);
    save_clr_cmp_cntl = regr (CLR_CMP_CNTL);
    save_scale_3d_cntl = regr (SCALE_3D_CNTL);
    save_tex_cntl = regr (TEX_CNTL);

    // disable any 3D stuff happening.
    regw (SCALE_3D_CNTL, 0x00000000);
    R128_WaitForIdle ();

    // clear colour compare cntl
    regw (CLR_CMP_CNTL, 0x00000000);

    // We will use a 32x32 mono pattern, expanding it to the foreground,
    // and the background may or may not be expanded as well.
    // set DP_DATATYPE to satisfy the above conditions.
    bppvalue = R128_GetBPPValue (R128_AdapterInfo.bpp);
    if (transparent)
    {
        brush = BRUSH_32x32MONO_LBKGD;
    }
    else
    {
        brush = BRUSH_32x32MONO;
    }

    regw (DP_DATATYPE, SRC_MONO | brush | bppvalue);
    regw (DP_MIX, ROP3_PATCOPY | DP_SRC_RECT);
    regw (DP_BRUSH_FRGD_CLR, R128_GetColourCode (foreground));
    regw (DP_BRUSH_BKGD_CLR, R128_GetColourCode (background));

    // now render the text
    length = strlen (data);
    for (loop=0; loop<length; loop++)
    {
        PrintChar (data[loop], x + (loop * TEXT_INFO.actual_width), y);
    }

    R128_WaitForFifo (4);

    regw (SCALE_3D_CNTL, save_scale_3d_cntl);
    regw (DP_DATATYPE, save_dp_datatype);
    regw (DP_MIX, save_dp_mix);
    regw (CLR_CMP_CNTL, save_clr_cmp_cntl);

    return;
}

/****************************************************************************
 * PrintChar (char ch, WORD x, WORD y)                                      *
 *  Function: prints a character to the screen.                             *
 *    Inputs: char ch - the character to be printed                         *
 *            WORD x - X location where the character will be printed       *
 *            WORD y - Y location where the character will be printed       *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void PrintChar (char ch, WORD x, WORD y)
{
    WORD offset, row, column, location, i;
    BYTE b0, b1, b2, b3;
    WORD shiftx, shifty;
    DWORD temp, regoffset;

    // check for special characters first
    if (isspace (ch))
    {
        PrintSpace (x, y);
        return;
    }

    if (ch == ':')
    {
        PrintColon (x, y);
        return;
    }


    if (isupper (ch))
    {
        row = 1;
        offset = 65;
    }
    else
    {
        row = 0;
        offset = 97;
    }

    if (isdigit (ch))
    {
        row = 2;
        offset = 48;
    }

    column = ch - offset;
    // calculate where in the text_data array this letter starts
    location = (row * 26*TEXT_INFO.width/8*TEXT_INFO.height) +
                    (column * TEXT_INFO.width/8);

    // since we're using a 32x32 brush, we must load 32 DWORDs into the
    // brush data registers.
    for (i = 0; i < 32; i++)
    {
        R128_WaitForFifo (1);
        regoffset = BRUSH_DATA0 + (i * 4);
        b0 = text_data[location];
        b1 = text_data[location+1];
        b2 = text_data[location+2];
        b3 = text_data[location+3];
        temp = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
        regw (regoffset, temp);
        location+= 26*TEXT_INFO.width/8;
    }

    // now do a 16x9 blt!
    // shiftx determines how much we will have to shift the brushes
    // to position the pattern at the right edge of the rectangle
    shiftx = 32 - x%32;

    // shifty determines how much we will have to shift the brushes
    // to position the pattern at the top edge of the rectangle
    shifty = 32 - y%32;

    R128_WaitForFifo (3);
    // We will adjust the brushes so that the pattern
    // is always starting in the top right of the rectangle
    regw (BRUSH_Y_X, (shifty << 8) | shiftx);
    regw (DST_Y_X, (y << 16) | x);
    regw (DST_HEIGHT_WIDTH, (TEXT_INFO.height << 16) | TEXT_INFO.actual_width);

    return;

} // PrintChar ()


/****************************************************************************
 * PrintSpace (WORD x, WORD y)                                              *
 *  Function: prints a space to the screen.                                 *
 *    Inputs: WORD x - X location where the space will be printed           *
 *            WORD y - Y location where the space will be printed           *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void PrintSpace (WORD x, WORD y)
{
    WORD loop;
    DWORD regoffset;

    // setup the brush data registers to print a space
    // i.e. load 0s in the first 32 brush data registers
    for (loop = 0; loop < 32; loop++)
    {
        R128_WaitForFifo (1);
        regoffset = BRUSH_DATA0 + (loop * 4);
        regw (regoffset, 0x00000000);
    }

    regw (DST_Y_X, (y << 16) | x);
    regw (DST_HEIGHT_WIDTH, (TEXT_INFO.height << 16) | TEXT_INFO.actual_width);

    return;
} // PrintSpace ()


/****************************************************************************
 * PrintColon (WORD x, WORD y)                                              *
 *  Function: prints a colon to the screen.                                 *
 *    Inputs: WORD x - X location where the colon will be printed           *
 *            WORD y - Y location where the colon will be printed           *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void PrintColon (WORD x, WORD y)
{
    WORD loop;
    DWORD regoffset;

    // setup the brush data registers to print a colon
    for (loop = 0; loop < 32; loop++)
    {
        R128_WaitForFifo (1);
        regoffset = BRUSH_DATA0 + (loop * 4);
        if (TEXT_INFO.height == 16)
        {
            regw (regoffset, colon16[loop]);
        }
        else
        {
            regw (regoffset, colon32[loop]);
        }
    }

    regw (DST_Y_X, (y << 16) | x);
    regw (DST_HEIGHT_WIDTH, (TEXT_INFO.height << 16) | TEXT_INFO.actual_width);

    return;
} // PrintColon ()
