//*****************************************************************************
//
// offscr1bpp.c - 1 BPP off-screen display buffer driver.
//
// Copyright (c) 2008-2020 Texas Instruments Incorporated.  All rights reserved.
// Software License Agreement
// 
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
// 
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
// 
// This is part of revision 2.2.0.295 of the Tiva Graphics Library.
//
//*****************************************************************************

#include <stdint.h>
#include <stdbool.h>
#include "driverlib/debug.h"
#include "grlib/grlib.h"

//*****************************************************************************
//
//! \addtogroup primitives_api
//! @{
//
//*****************************************************************************

//*****************************************************************************
//
// Translates a 24-bit RGB color to a display driver-specific color.
//
// \param c is the 24-bit RGB color.  The least-significant byte is the blue
// channel, the next byte is the green channel, and the third byte is the red
// channel.
//
// This macro translates a 24-bit RGB color into a value that can be written
// into the display's frame buffer in order to reproduce that color, or the
// closest possible approximation of that color.
//
// \return Returns the display-driver specific color.
//
//*****************************************************************************
#define DPYCOLORTRANSLATE(c)    ((((((c) & 0x00ff0000) >> 16) * 19661) + \
                                  ((((c) & 0x0000ff00) >> 8) * 38666) +  \
                                  (((c) & 0x000000ff) * 7209)) /         \
                                 (65536 * 128))

//*****************************************************************************
//
//! Draws a pixel on the screen.
//!
//! \param pvDisplayData is a pointer to the driver-specific data for this
//! display driver.
//! \param i32X is the X coordinate of the pixel.
//! \param i32Y is the Y coordinate of the pixel.
//! \param ui32Value is the color of the pixel.
//!
//! This function sets the given pixel to a particular color.  The coordinates
//! of the pixel are assumed to be within the extents of the display.
//!
//! \return None.
//
//*****************************************************************************
static void
GrOffScreen1BPPPixelDraw(void *pvDisplayData, int32_t i32X, int32_t i32Y,
                           uint32_t ui32Value)
{
    uint8_t *pui8Data;
    int32_t i32BytesPerRow;

    //
    // Check the arguments.
    //
    ASSERT(pvDisplayData);

    //
    // Create a character pointer for the display-specific data (which points
    // to the image buffer).
    //
    pui8Data = (uint8_t *)pvDisplayData;

    //
    // Compute the number of bytes per row in the image buffer.
    //
    i32BytesPerRow = (*(uint16_t *)(pui8Data + 1) + 7) / 8;

    //
    // Get the offset to the byte of the image buffer that contains the pixel
    // in question.
    //
    pui8Data += (i32BytesPerRow * i32Y) + (i32X / 8) + 5;

    //
    // Determine how much to shift to get to the bit that contains this pixel.
    //
    i32X = 7 - (i32X & 7);

    //
    // Write this pixel into the image buffer.
    //
    *pui8Data = (*pui8Data & ~(1 << i32X)) | (ui32Value << i32X);
}

//*****************************************************************************
//
//! Draws a horizontal sequence of pixels on the screen.
//!
//! \param pvDisplayData is a pointer to the driver-specific data for this
//! display driver.
//! \param i32X is the X coordinate of the first pixel.
//! \param i32Y is the Y coordinate of the first pixel.
//! \param i32X0 is sub-pixel offset within the pixel data, which is valid for
//! 1 or 4 bit per pixel formats.
//! \param i32Count is the number of pixels to draw.
//! \param i32BPP is the number of bits per pixel ORed with a flag indicating
//! whether or not this run represents the start of a new image.
//! \param pui8Data is a pointer to the pixel data.  For 1 and 4 bit per pixel
//! formats, the most significant bit(s) represent the left-most pixel.
//! \param pui8Palette is a pointer to the palette used to draw the pixels.
//!
//! This function draws a horizontal sequence of pixels on the screen, using
//! the supplied palette.  For 1 bit per pixel format, the palette contains
//! pre-translated colors; for 4 and 8 bit per pixel formats, the palette
//! contains 24-bit RGB values that must be translated before being written to
//! the display.
//!
//! The \e i32BPP parameter will take the value 1, 4 or 8 and may be ORed with
//! \b GRLIB_DRIVER_FLAG_NEW_IMAGE to indicate that this run represents the
//! start of a new image.  Drivers which make use of lookup tables to convert
//! from the source to destination pixel values should rebuild their lookup
//! table when \b GRLIB_DRIVER_FLAG_NEW_IMAGE is set.
//!
//! \return None.
//
//*****************************************************************************
static void
GrOffScreen1BPPPixelDrawMultiple(void *pvDisplayData, int32_t i32X,
                                   int32_t i32Y, int32_t i32X0,
                                   int32_t i32Count, int32_t i32BPP,
                                   const uint8_t *pui8Data,
                                   const uint8_t *pui8Palette)
{
    uint8_t *pui8Ptr;
    uint32_t ui32Byte;
    int32_t i32BytesPerRow;

    //
    // Check the arguments.
    //
    ASSERT(pvDisplayData);
    ASSERT(pui8Data);
    ASSERT(pui8Palette);

    //
    // Create a character pointer for the display-specific data (which points
    // to the image buffer).
    //
    pui8Ptr = (uint8_t *)pvDisplayData;

    //
    // Compute the number of bytes per row in the image buffer.
    //
    i32BytesPerRow = (*(uint16_t *)(pui8Ptr + 1) + 7) / 8;

    //
    // Get the offset to the byte of the image buffer that contains the
    // starting pixel.
    //
    pui8Ptr += (i32BytesPerRow * i32Y) + (i32X / 8) + 5;

    //
    // Determine the bit position of the starting pixel.
    //
    i32X = 7 - (i32X & 7);

    //
    // Determine how to interpret the pixel data based on the number of bits
    // per pixel.
    //
    switch(i32BPP & 0xFF)
    {
        //
        // The pixel data is in 1 bit per pixel format.
        //
        case 1:
        {
            //
            // Loop while there are more pixels to draw.
            //
            while(i32Count)
            {
                //
                // Get the next byte of image data.
                //
                ui32Byte = *pui8Data++;

                //
                // Loop through the pixels in this byte of image data.
                //
                for(; (i32X0 < 8) && i32Count; i32X0++, i32Count--)
                {
                    //
                    // Draw this pixel in the appropriate color.
                    //
                    *pui8Ptr = ((*pui8Ptr & ~(1 << i32X)) |
                               ((((uint32_t *)pui8Palette)[(ui32Byte >>
                                                                (7 - i32X0)) &
                                                               1]) << i32X));
                    if(i32X-- == 0)
                    {
                        i32X = 7;
                        pui8Ptr++;
                    }
                }

                //
                // Start at the beginning of the next byte of image data.
                //
                i32X0 = 0;
            }

            //
            // The image data has been drawn.
            //
            break;
        }

        //
        // The pixel data is in 4 bit per pixel format.
        //
        case 4:
        {
            //
            // Loop while there are more pixels to draw.  "Duff's device" is
            // used to jump into the middle of the loop if the first nibble of
            // the pixel data should not be used.  Duff's device makes use of
            // the fact that a case statement is legal anywhere within a
            // sub-block of a switch statement.  See
            // http://en.wikipedia.org/wiki/Duff's_device for detailed
            // information about Duff's device.
            //
            switch(i32X0 & 1)
            {
                case 0:
                    while(i32Count)
                    {
                        //
                        // Get the upper nibble of the next byte of pixel data
                        // and extract the corresponding entry from the
                        // palette.
                        //
                        ui32Byte = (*pui8Data >> 4) * 3;
                        ui32Byte = (*(uint32_t *)(pui8Palette + ui32Byte) &
                                    0x00ffffff);

                        //
                        // Translate this palette entry and write it to the
                        // screen.
                        //
                        *pui8Ptr = ((*pui8Ptr & ~(1 << i32X)) |
                                   (DPYCOLORTRANSLATE(ui32Byte) << i32X));
                        if(i32X-- == 0)
                        {
                            i32X = 7;
                            pui8Ptr++;
                        }

                        //
                        // Decrement the count of pixels to draw.
                        //
                        i32Count--;

                        //
                        // See if there is another pixel to draw.
                        //
                        if(i32Count)
                        {
                case 1:
                            //
                            // Get the lower nibble of the next byte of pixel
                            // data and extract the corresponding entry from
                            // the palette.
                            //
                            ui32Byte = (*pui8Data++ & 15) * 3;
                            ui32Byte = (*(uint32_t *)(pui8Palette + ui32Byte) &
                                      0x00ffffff);

                            //
                            // Translate this palette entry and write it to the
                            // screen.
                            //
                            *pui8Ptr = ((*pui8Ptr & ~(1 << i32X)) |
                                       (DPYCOLORTRANSLATE(ui32Byte) << i32X));
                            if(i32X-- == 0)
                            {
                                i32X = 7;
                                pui8Ptr++;
                            }

                            //
                            // Decrement the count of pixels to draw.
                            //
                            i32Count--;
                        }
                    }
            }

            //
            // The image data has been drawn.
            //
            break;
        }

        //
        // The pixel data is in 8 bit per pixel format.
        //
        case 8:
        {
            //
            // Loop while there are more pixels to draw.
            //
            while(i32Count--)
            {
                //
                // Get the next byte of pixel data and extract the
                // corresponding entry from the palette.
                //
                ui32Byte = *pui8Data++ * 3;
                ui32Byte = *(uint32_t *)(pui8Palette + ui32Byte) & 0x00ffffff;

                //
                // Translate this palette entry and write it to the screen.
                //
                *pui8Ptr = ((*pui8Ptr & ~(1 << i32X)) |
                           (DPYCOLORTRANSLATE(ui32Byte) << i32X));
                if(i32X-- == 0)
                {
                    i32X = 7;
                    pui8Ptr++;
                }
            }

            //
            // The image data has been drawn.
            //
            break;
        }
    }
}

//*****************************************************************************
//
//! Draws a horizontal line.
//!
//! \param pvDisplayData is a pointer to the driver-specific data for this
//! display driver.
//! \param i32X1 is the X coordinate of the start of the line.
//! \param i32X2 is the X coordinate of the end of the line.
//! \param i32Y is the Y coordinate of the line.
//! \param ui32Value is the color of the line.
//!
//! This function draws a horizontal line on the display.  The coordinates of
//! the line are assumed to be within the extents of the display.
//!
//! \return None.
//
//*****************************************************************************
static void
GrOffScreen1BPPLineDrawH(void *pvDisplayData, int32_t i32X1, int32_t i32X2,
                         int32_t i32Y, uint32_t ui32Value)
{
    int32_t i32BytesPerRow, i32Mask;
    uint8_t *pui8Data;

    //
    // Check the arguments.
    //
    ASSERT(pvDisplayData);

    //
    // Create a character pointer for the display-specific data (which points
    // to the image buffer).
    //
    pui8Data = (uint8_t *)pvDisplayData;

    //
    // Compute the number of bytes per row in the image buffer.
    //
    i32BytesPerRow = (*(uint16_t *)(pui8Data + 1) + 7) / 8;

    //
    // Get the offset to the byte of the image buffer that contains the
    // starting pixel.
    //
    pui8Data += (i32BytesPerRow * i32Y) + (i32X1 / 8) + 5;

    //
    // Copy the pixel value into all 32 pixels of the uint32_t.  This will
    // be used later to write multiple pixels into memory (as opposed to one at
    // a time).
    //
    if(ui32Value)
    {
        ui32Value = 0xffffffff;
    }

    //
    // See if the current buffer byte contains pixels that should be left
    // unmodified.
    //
    if(i32X1 & 7)
    {
        //
        // Compute the mask to access only the appropriate pixels within this
        // byte.  The line may start and stop within this byte, so the mask may
        // need to be shortened to account for this situation.
        //
        i32Mask = 8 - (i32X1 & 7);
        if(i32Mask > (i32X2 - i32X1 + 1))
        {
            i32Mask = i32X2 - i32X1 + 1;
        }
        i32Mask = ((1 << i32Mask) - 1) << (8 - (i32X1 & 7) - i32Mask);

        //
        // Draw the appropriate pixels within this byte.
        //
        *pui8Data = (*pui8Data & ~i32Mask) | (ui32Value & i32Mask);
        pui8Data++;
        i32X1 = (i32X1 + 7) & ~7;
    }

    //
    // See if the buffer pointer is not half-word aligned and there are at
    // least eight pixels left to draw.
    //
    if(((uint32_t)pui8Data & 1) && ((i32X2 - i32X1) > 6))
    {
        //
        // Draw eight pixels to half-word align the buffer pointer.
        //
        *pui8Data++ = ui32Value & 0xff;
        i32X1 += 8;
    }

    //
    // See if the buffer pointer is not word aligned and there are at least
    // sixteen pixels left to draw.
    //
    if(((uint32_t)pui8Data & 2) && ((i32X2 - i32X1) > 14))
    {
        //
        // Draw sixteen pixels to word align the buffer pointer.
        //
        *(uint16_t *)pui8Data = ui32Value & 0xffff;
        pui8Data += 2;
        i32X1 += 16;
    }

    //
    // Loop while there are at least thirty two pixels left to draw.
    //
    while((i32X1 + 31) <= i32X2)
    {
        //
        // Draw thirty two pixels.
        //
        *(uint32_t *)pui8Data = ui32Value;
        pui8Data += 4;
        i32X1 += 32;
    }

    //
    // See if there are at least sixteen pixels left to draw.
    //
    if((i32X1 + 15) <= i32X2)
    {
        //
        // Draw sixteen pixels, leaving the buffer pointer half-word aligned.
        //
        *(uint16_t *)pui8Data = ui32Value & 0xffff;
        pui8Data += 2;
        i32X1 += 16;
    }

    //
    // See if there are at least eight pixels left to draw.
    //
    if((i32X1 + 7) <= i32X2)
    {
        //
        // Draw eight pixels, leaving the buffer pointer byte aligned.
        //
        *pui8Data++ = ui32Value & 0xff;
        i32X1 += 8;
    }

    //
    // See if there are any pixels left to draw.
    //
    if(i32X1 <= i32X2)
    {
        //
        // Draw the remaining pixels.
        //
        i32Mask = 0xff >> (i32X2 - i32X1 + 1);
        *pui8Data = (*pui8Data & i32Mask) | (ui32Value & ~i32Mask);
    }
}

//*****************************************************************************
//
//! Draws a vertical line.
//!
//! \param pvDisplayData is a pointer to the driver-specific data for this
//! display driver.
//! \param i32X is the X coordinate of the line.
//! \param i32Y1 is the Y coordinate of the start of the line.
//! \param i32Y2 is the Y coordinate of the end of the line.
//! \param ui32Value is the color of the line.
//!
//! This function draws a vertical line on the display.  The coordinates of the
//! line are assumed to be within the extents of the display.
//!
//! \return None.
//
//*****************************************************************************
static void
GrOffScreen1BPPLineDrawV(void *pvDisplayData, int32_t i32X, int32_t i32Y1,
                         int32_t i32Y2, uint32_t ui32Value)
{
    uint8_t *pui8Data;
    int32_t i32BytesPerRow;

    //
    // Check the arguments.
    //
    ASSERT(pvDisplayData);

    //
    // Create a character pointer for the display-specific data (which points
    // to the image buffer).
    //
    pui8Data = (uint8_t *)pvDisplayData;

    //
    // Compute the number of bytes per row in the image buffer.
    //
    i32BytesPerRow = (*(uint16_t *)(pui8Data + 1) + 7) / 8;

    //
    // Get the offset to the byte of the image buffer that contains the
    // starting pixel.
    //
    pui8Data += (i32BytesPerRow * i32Y1) + (i32X / 8) + 5;

    //
    // Determine how much to shift to get to the bit that contains this pixel.
    //
    i32X = 7 - (i32X & 7);

    //
    // Shift the pixel value up to the correct bit position, and create a mask
    // to preserve the value of the remaining pixels.
    //
    ui32Value <<= i32X;
    i32X = ~(1 << i32X);

    //
    // Loop over the rows of the line.
    //
    for(; i32Y1 <= i32Y2; i32Y1++)
    {
        //
        // Draw this pixel of the line.
        //
        *pui8Data = (*pui8Data & i32X) | ui32Value;
        pui8Data += i32BytesPerRow;
    }
}

//*****************************************************************************
//
//! Fills a rectangle.
//!
//! \param pvDisplayData is a pointer to the driver-specific data for this
//! display driver.
//! \param pRect is a pointer to the structure describing the rectangle.
//! \param ui32Value is the color of the rectangle.
//!
//! This function fills a rectangle on the display.  The coordinates of the
//! rectangle are assumed to be within the extents of the display, and the
//! rectangle specification is fully inclusive (in other words, both i16XMin
//! and i16XMax are drawn, along with i16YMin and i16YMax).
//!
//! \return None.
//
//*****************************************************************************
static void
GrOffScreen1BPPRectFill(void *pvDisplayData, const tRectangle *pRect,
                        uint32_t ui32Value)
{
    uint8_t *pui8Data, *pui8Column;
    int32_t i32BytesPerRow, i32Mask, i32X, i32Y;

    //
    // Check the arguments.
    //
    ASSERT(pvDisplayData);
    ASSERT(pRect);

    //
    // Create a character pointer for the display-specific data (which points
    // to the image buffer).
    //
    pui8Data = (uint8_t *)pvDisplayData;

    //
    // Compute the number of bytes per row in the image buffer.
    //
    i32BytesPerRow = (*(uint16_t *)(pui8Data + 1) + 7) / 8;

    //
    // Get the offset to the byte of the image buffer that contains the
    // starting pixel.
    //
    pui8Data += (i32BytesPerRow * pRect->i16YMin) + (pRect->i16XMin / 8) + 5;

    //
    // Copy the pixel value into all 32 pixels of the uint32_t.  This will
    // be used later to write multiple pixels into memory (as opposed to one at
    // a time).
    //
    if(ui32Value)
    {
        ui32Value = 0xffffffff;
    }

    //
    // Get the starting X coordinate of the rectangle.
    //
    i32X = pRect->i16XMin;

    //
    // See if the current buffer byte contains pixel columns that should be
    // left unmodified.
    //
    if(i32X & 7)
    {
        //
        // Compute the mask to access only the appropriate pixels within this
        // byte column.  The rectangle may start and stop within this byte
        // column, so the mask may need to be int16_tened to account for this
        // situation.
        //
        i32Mask = 8 - (i32X & 7);
        if(i32Mask > (pRect->i16XMax - i32X + 1))
        {
            i32Mask = pRect->i16XMax - i32X + 1;
        }
        i32Mask = ((1 << i32Mask) - 1) << (8 - (i32X & 7) - i32Mask);

        //
        // Draw the appropriate pixels within this column.
        //
        for(i32Y = pRect->i16YMin, pui8Column = pui8Data;
            i32Y <= pRect->i16YMax;
            i32Y++, pui8Column += i32BytesPerRow)
        {
            *pui8Column = (*pui8Column & ~i32Mask) | (ui32Value & i32Mask);
        }
        pui8Data++;
        i32X = (i32X + 7) & ~7;
    }

    //
    // See if the buffer pointer is not half-word aligned and there are at
    // least eight pixel columns left to draw.
    //
    if(((uint32_t)pui8Data & 1) && ((pRect->i16XMax - i32X) > 6))
    {
        //
        // Draw eight pixel columns to half-word align the buffer pointer.
        //
        for(i32Y = pRect->i16YMin, pui8Column = pui8Data;
            i32Y <= pRect->i16YMax;
            i32Y++, pui8Column += i32BytesPerRow)
        {
            *pui8Column = ui32Value & 0xff;
        }
        pui8Data++;
        i32X += 8;
    }

    //
    // See if the buffer pointer is not word aligned and there are at least
    // sixteen pixel columns left to draw.
    //
    if(((uint32_t)pui8Data & 2) && ((pRect->i16XMax - i32X) > 14))
    {
        //
        // Draw sixteen pixel columns to word align the buffer pointer.
        //
        for(i32Y = pRect->i16YMin, pui8Column = pui8Data;
            i32Y <= pRect->i16YMax;
            i32Y++, pui8Column += i32BytesPerRow)
        {
            *(uint16_t *)pui8Column = ui32Value & 0xffff;
        }
        pui8Data += 2;
        i32X += 16;
    }

    //
    // Loop while there are at least thirty two pixel columnss left to draw.
    //
    while((i32X + 31) <= pRect->i16XMax)
    {
        //
        // Draw thirty two pixel columnss.
        //
        for(i32Y = pRect->i16YMin, pui8Column = pui8Data;
            i32Y <= pRect->i16YMax;
            i32Y++, pui8Column += i32BytesPerRow)
        {
            *(uint32_t *)pui8Column = ui32Value;
        }
        pui8Data += 4;
        i32X += 32;
    }

    //
    // See if there are at least sixteen pixel columnss left to draw.
    //
    if((i32X + 15) <= pRect->i16XMax)
    {
        //
        // Draw sixteen pixel columns, leaving the buffer pointer half-word
        // aligned.
        //
        ui32Value &= 0xffff;
        for(i32Y = pRect->i16YMin, pui8Column = pui8Data;
            i32Y <= pRect->i16YMax;
            i32Y++, pui8Column += i32BytesPerRow)
        {
            *(uint16_t *)pui8Column = ui32Value;
        }
        pui8Data += 2;
        i32X += 16;
    }

    //
    // See if there are at least eight pixel columns left to draw.
    //
    if((i32X + 7) <= pRect->i16XMax)
    {
        //
        // Draw eight pixel columns, leaving the buffer pointer byte aligned.
        //
        ui32Value &= 0xff;
        for(i32Y = pRect->i16YMin, pui8Column = pui8Data;
            i32Y <= pRect->i16YMax;
            i32Y++, pui8Column += i32BytesPerRow)
        {
            *pui8Column = ui32Value;
        }
        pui8Data++;
        i32X += 8;
    }

    //
    // See if there are any pixel columns left to draw.
    //
    if(i32X <= pRect->i16XMax)
    {
        //
        // Draw the remaining pixel columns.
        //
        i32Mask = 0xff >> (pRect->i16XMax - i32X + 1);
        ui32Value &= ~i32Mask;
        for(i32Y = pRect->i16YMin; i32Y <= pRect->i16YMax;
            i32Y++, pui8Data += i32BytesPerRow)
        {
            *pui8Data = (*pui8Data & i32Mask) | ui32Value;
        }
    }
}

//*****************************************************************************
//
//! Translates a 24-bit RGB color to a display driver-specific color.
//!
//! \param pvDisplayData is a pointer to the driver-specific data for this
//! display driver.
//! \param ui32Value is the 24-bit RGB color.  The least-significant byte is
//! the blue channel, the next byte is the green channel, and the third byte is
//! the red channel.
//!
//! This function translates a 24-bit RGB color into a value that can be
//! written into the display's frame buffer in order to reproduce that color,
//! or the closest possible approximation of that color.
//!
//! \return Returns the display-driver specific color.
//
//*****************************************************************************
static uint32_t
GrOffScreen1BPPColorTranslate(void *pvDisplayData, uint32_t ui32Value)
{
    //
    // Check the arguments.
    //
    ASSERT(pvDisplayData);

    //
    // Translate from a 24-bit RGB color to black or white.
    //
    return(DPYCOLORTRANSLATE(ui32Value));
}

//*****************************************************************************
//
//! Flushes any cached drawing operations.
//!
//! \param pvDisplayData is a pointer to the driver-specific data for this
//! display driver.
//!
//! This functions flushes any cached drawing operations to the display.  This
//! is useful when a local frame buffer is used for drawing operations, and the
//! flush would copy the local frame buffer to the display.  For the off-screen
//! display buffer driver, the flush is a no operation.
//!
//! \return None.
//
//*****************************************************************************
static void
GrOffScreen1BPPFlush(void *pvDisplayData)
{
    //
    // Check the arguments.
    //
    ASSERT(pvDisplayData);
}

//*****************************************************************************
//
//! Initializes a 1 BPP off-screen buffer.
//!
//! \param psDisplay is a pointer to the display structure to be configured for
//! the 1 BPP off-screen buffer.
//! \param pui8Image is a pointer to the image buffer to be used for the
//! off-screen buffer.
//! \param i32Width is the width of the image buffer in pixels.
//! \param i32Height is the height of the image buffer in pixels.
//!
//! This function initializes a display structure, preparing it to draw into
//! the supplied image buffer.  The image buffer is assumed to be large enough
//! to hold an image of the specified geometry.
//!
//! \return None.
//
//*****************************************************************************
void
GrOffScreen1BPPInit(tDisplay *psDisplay, uint8_t *pui8Image, int32_t i32Width,
                    int32_t i32Height)
{
    //
    // Check the arguments.
    //
    ASSERT(psDisplay);
    ASSERT(pui8Image);

    //
    // Initialize the display structure.
    //
    psDisplay->i32Size = sizeof(tDisplay);
    psDisplay->pvDisplayData = pui8Image;
    psDisplay->ui16Width = i32Width;
    psDisplay->ui16Height = i32Height;
    psDisplay->pfnPixelDraw = GrOffScreen1BPPPixelDraw;
    psDisplay->pfnPixelDrawMultiple = GrOffScreen1BPPPixelDrawMultiple;
    psDisplay->pfnLineDrawH = GrOffScreen1BPPLineDrawH;
    psDisplay->pfnLineDrawV = GrOffScreen1BPPLineDrawV;
    psDisplay->pfnRectFill = GrOffScreen1BPPRectFill;
    psDisplay->pfnColorTranslate = GrOffScreen1BPPColorTranslate;
    psDisplay->pfnFlush = GrOffScreen1BPPFlush;

    //
    // Initialize the image buffer.
    //
    pui8Image[0] = IMAGE_FMT_1BPP_UNCOMP;
    *(uint16_t *)(pui8Image + 1) = i32Width;
    *(uint16_t *)(pui8Image + 3) = i32Height;
}

//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
