//****************************************************************************
//
// LCD.C - General drawing routines.
//
// Copyright (c) 1998-1999 Cirrus Logic, Inc.
//
//****************************************************************************
#include "lib7209.h"
#include "font.h"

//****************************************************************************
//
// LCDLine draws a line from (lX1, lY1) to (lX2, lY2).  This is an
// implementation of Bresenham's line drawing algorithm; for details, see any
// reputable graphics book.
//
//****************************************************************************
void
LCDLine(long lX1, long lY1, long lX2, long lY2, USIGN16  cColor)
{       
    long lX, lY, lXend, lYend, lDx, lDy, lD, lXinc, lYinc, lIncr1, lIncr2;

    lDx = lX2 > lX1 ? lX2 - lX1 : lX1 - lX2;
    lDy = lY2 > lY1 ? lY2 - lY1 : lY1 - lY2;
    
    if(lDx >= lDy)
    {
        if(lX1 > lX2)
        {
            lX = lX2;
            lY = lY2;
            lXend = lX1;

            if(lDy == 0)
            {
                lYinc = 0;
            }
            else
            {
                if(lY2 > lY1)
                {
                    lYinc = -1;
                }
                else
                {
                    lYinc = 1;
                }
            }
        }
        else
        {
            lX = lX1;
            lY = lY1;
            lXend = lX2;

            if(lDx == 0)
            {
                lYinc = 0;
            }
            else
            {
                if(lY2 > lY1)
                {
                    lYinc = 1;
                }
                else
                {
                    lYinc = -1;
                }
            }
        }

        lIncr1 = 2 * lDy;
        lD = lIncr1 - lDx;
        lIncr2 = 2 * (lDy - lDx);

        LCDSetPixel(lX, lY, cColor);

        while(lX < lXend)
        {
            lX++;

            if(lD < 0)
            {
                lD += lIncr1;
            }
            else
            {
                lY += lYinc;      
                lD += lIncr2;
            }

            LCDSetPixel(lX, lY, cColor);
        }
    }
    else
    {
        if(lY1 > lY2)
        {
            lX = lX2;
            lY = lY2;
            lYend = lY1;

            if(lDx == 0)
            {
                lXinc = 0;
            }
            else
            {
                if(lX2 > lX1)
                {
                    lXinc = -1;
                }
                else
                {
                    lXinc = 1;
                }
            }
        }
        else
        {
            lX = lX1;
            lY = lY1;
            lYend = lY2;

            if(lDx == 0)
            {
                lXinc = 0;
            }
            else
            {
                if(lX2 > lX1)
                {
                    lXinc = 1;
                }
                else
                {
                    lXinc = -1;
                }
            }
        }

        lIncr1 = 2 * lDx;
        lD = lIncr1 - lDy;
        lIncr2 = 2 * (lDx - lDy);

        LCDSetPixel(lX, lY, cColor);

        while(lY < lYend)
        {
            lY++;

            if(lD < 0)
            {
                lD += lIncr1;
            }
            else
            {
                lX += lXinc;
                lD += lIncr2;
            }

            LCDSetPixel(lX, lY, cColor);
        }
    }
}

//****************************************************************************
//
// LCDCircle draws a circle at the specified location.  This is an
// implementation of Bresenham's circle drawing algorithm; for details, see
// any reputable graphics book.
//
//****************************************************************************
void
LCDCircle(long lX, long lY, long lRadius, USIGN16 cColor)
{
    long lXpos, lYpos, lD;

    lXpos = 0;
    lYpos = lRadius;

    lD = 3 - (2 * lYpos);

    while(lYpos >= lXpos)
    {
        LCDSetPixel(lX + lXpos, lY + lYpos, cColor);
        LCDSetPixel(lX + lYpos, lY + lXpos, cColor);
        LCDSetPixel(lX + lXpos, lY - lYpos, cColor);
        LCDSetPixel(lX - lYpos, lY + lXpos, cColor);
        LCDSetPixel(lX - lXpos, lY - lYpos, cColor);
        LCDSetPixel(lX - lYpos, lY - lXpos, cColor);
        LCDSetPixel(lX - lXpos, lY + lYpos, cColor);
        LCDSetPixel(lX + lYpos, lY - lXpos, cColor);

        if(lD < 0)
        {
            lD += (4 * lXpos) + 6;
        }
        else
        {
            lD += 10 + (4 * (lXpos - lYpos));
            lYpos--;
        }

        lXpos++;
    }
}

//****************************************************************************
//
// LCDFillCircle draws a filled circle at the specified location.  This is an
// implementation of Bresenham's circle drawing algorithm; for details, see
// any reputable graphics book.
//
//****************************************************************************
void
LCDFillCircle(long lX, long lY, long lRadius, USIGN16 cColor)
{
    long lXpos, lYpos, lD;

    lXpos = 0;
    lYpos = lRadius;

    lD = 3 - (2 * lYpos);

    while(lYpos >= lXpos)
    {
        LCDLine(lX - lXpos, lY + lYpos, lX + lXpos, lY + lYpos, cColor);
        LCDLine(lX - lYpos, lY + lXpos, lX + lYpos, lY + lXpos, cColor);
        LCDLine(lX - lXpos, lY - lYpos, lX + lXpos, lY - lYpos, cColor);
        LCDLine(lX - lYpos, lY - lXpos, lX + lYpos, lY - lXpos, cColor);

        if(lD < 0)
        {
            lD += (4 * lXpos) + 6;
        }
        else
        {
            lD += 10 + (4 * (lXpos - lYpos));
            lYpos--;
        }

        lXpos++;
    }
}

//****************************************************************************
//
// LCDPrintChar prints a character at the specified location.
//
//****************************************************************************
void
LCDPrintChar(char cChar, long lX, long lY, USIGN16 cColor)
{
    long lIdx1, lIdx2;
    char cFontLine;

    //
    // The character font is 8x8, so loop through each row of the font.
    //
    for(lIdx1 = 0; lIdx1 < 8; lIdx1++)
    {
        //
        // Read the byte which describes this row of the font.
        //
        cFontLine = FontData[(cChar << 3) + lIdx1];

        //
        // Loop through each column of this row.
        //
        for(lIdx2 = 0; lIdx2 < 8; lIdx2++)
        {
            //
            // Set the pixel for this row,column based on the value of this
            // bit of the font.
            //
            LCDSetPixel(lX + lIdx2, lY + lIdx1,
                        cFontLine & 1 << (7 - lIdx2) ? cColor : 0);
        }
    }
}

//****************************************************************************
//
// LCDPrintString prints a string at the specified location.
//
//****************************************************************************
void
LCDPrintString(char *pcBuffer, long lX, long lY, USIGN16 cColor)
{
    //
    // Loop through each character in the string.
    //
    while(*pcBuffer)
    {
        //
        // Print this character.
        //
        LCDPrintChar(*pcBuffer++, lX, lY, cColor);

        //
        // Advance horizontally past this character.
        //
        lX += 8;
    }
}

//****************************************************************************
//
// LCDPrintCharX2 prints a double-sized character at the specified location.
//
//****************************************************************************
void
LCDPrintCharX2(char cChar, long lX, long lY, USIGN16 cColor)
{
    long lIdx1, lIdx2;
    char cFontLine, cPixelColor;

    //
    // The character font is 8x8, so loop through each row of the font.
    //
    for(lIdx1 = 0; lIdx1 < 8; lIdx1++)
    {
        //
        // Read the byte which describes this row of the font.
        //
        cFontLine = FontData[(cChar << 3) + lIdx1];

        //
        // Loop through each column of this row.
        //
        for(lIdx2 = 0; lIdx2 < 8; lIdx2++)
        {
            //
            // Determine the color of this pixel block.
            //
            cPixelColor = cFontLine & (1 << (7 - lIdx2)) ? cColor : 0;

            //
            // Set the pixel block for this row,column of the font.
            //
            LCDSetPixel(lX + (lIdx2 << 1), lY + (lIdx1 << 1), cPixelColor);
            LCDSetPixel(lX + (lIdx2 << 1) + 1, lY + (lIdx1 << 1), cPixelColor);
            LCDSetPixel(lX + (lIdx2 << 1), lY + (lIdx1 << 1) + 1, cPixelColor);
            LCDSetPixel(lX + (lIdx2 << 1) + 1, lY + (lIdx1 << 1) + 1,
                        cPixelColor);
        }
    }
}

//****************************************************************************
//
// LCDPrintStringX2 prints a string of double-sized characters at the
// specified location.
//
//****************************************************************************
void
LCDPrintStringX2(char *pcBuffer, long lX, long lY, USIGN16 cColor)
{
    //
    // Loop through each character in the string.
    //
    while(*pcBuffer)
    {
        //
        // Print this character.
        //
        LCDPrintCharX2(*pcBuffer++, lX, lY, cColor);

        //
        // Advance horizontally past this character.
        //
        lX += 16;
    }
}
