/* --COPYRIGHT--,BSD
|
|
* Copyright (c) 2013, Texas Instruments Incorporated
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* * Neither the name of Texas Instruments Incorporated nor the names of
|
|
* its contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
* --/COPYRIGHT--*/
|
|
|
|
#include "grlib.h"
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! \addtogroup image_api
|
|
//! @{
|
|
//
|
|
//*****************************************************************************
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// The buffer that holds the converted palette of the image to be drawn. This
|
|
// buffer contains the actual data to be written to the LCD after translation.
|
|
//
|
|
//*****************************************************************************
|
|
static unsigned int g_pulConvertedPalette[256];
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Converts the bitmap image palette.
|
|
//!
|
|
//! \param pContext is a pointer to the drawing context to use.
|
|
//! \param pBitmap is a pointer to the image.
|
|
//!
|
|
//! This function converts the palette of a bitmap image. The image palette is in
|
|
//! 24 bit RGB form, and this function converts that to a format to be sent to the
|
|
//! LCD using DpyColorTranslate function. The converted palette is contained in a
|
|
//! global buffer while the original image palette remains unchanged.
|
|
//!
|
|
//! \return is the address of the global buffer containing the converted palette.
|
|
//
|
|
//*****************************************************************************
|
|
unsigned int * GrPaletteConversion(const tContext *pContext, const tImage * pBitmap)
|
|
{
|
|
if (pBitmap->NumColors > 256)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int i;
|
|
int NumColors = pBitmap->NumColors;
|
|
const unsigned long * pulPalette = &pBitmap->pPalette[0];
|
|
for (i = 0; i < NumColors; i++)
|
|
{
|
|
g_pulConvertedPalette[i] = DpyColorTranslate(pContext->pDisplay, *(pulPalette + i));
|
|
}
|
|
return &g_pulConvertedPalette[0];
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Draws a bitmap image.
|
|
//!
|
|
//! \param pContext is a pointer to the drawing context to use.
|
|
//! \param pucImage is a pointer to the image to draw.
|
|
//! \param lX is the X coordinate of the upper left corner of the image.
|
|
//! \param lY is the Y coordinate of the upper left corner of the image.
|
|
//!
|
|
//! This function draws a bitmap image. The image may be 1 bit per pixel, 4
|
|
//! bits per pixel or 8 bits per pixel (using a palette supplied in the image
|
|
//! data). It can be uncompressed data, or it can be compressed using
|
|
//! several different compression types. Compression options are 4-bit run
|
|
//! length encoding, 8-bit run length encoding, and a custom run length encoding
|
|
//! variation written for complex 8-bit per pixel images.
|
|
//!
|
|
//! \return None.
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
GrImageDraw(const tContext *pContext, const tImage *pBitmap, int lX,
|
|
int lY)
|
|
{
|
|
int lBPP, lWidth, lHeight, lX0, lX1, lX2;
|
|
const unsigned int *pucPalette;
|
|
const unsigned char * pucImage;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
assert(pContext);
|
|
assert(pBitmap);
|
|
|
|
//
|
|
// Get the image format from the image data.
|
|
//
|
|
lBPP = pBitmap->BPP;
|
|
|
|
//
|
|
// Get the image width from the image data.
|
|
//
|
|
lWidth = pBitmap->XSize;
|
|
|
|
|
|
//
|
|
// Get the image height from the image data.
|
|
//
|
|
lHeight = pBitmap->YSize;
|
|
|
|
//
|
|
// Return without doing anything if the entire image lies outside the
|
|
// current clipping region.
|
|
//
|
|
if((lX > pContext->sClipRegion.sXMax) ||
|
|
((lX + lWidth - 1) < pContext->sClipRegion.sXMin) ||
|
|
(lY > pContext->sClipRegion.sYMax) ||
|
|
((lY + lHeight - 1) < pContext->sClipRegion.sYMin))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get the starting X offset within the image based on the current clipping
|
|
// region.
|
|
//
|
|
if(lX < pContext->sClipRegion.sXMin)
|
|
{
|
|
lX0 = pContext->sClipRegion.sXMin - lX;
|
|
}
|
|
else
|
|
{
|
|
lX0 = 0;
|
|
}
|
|
|
|
//
|
|
// Get the ending X offset within the image based on the current clipping
|
|
// region.
|
|
//
|
|
if((lX + lWidth - 1) > pContext->sClipRegion.sXMax)
|
|
{
|
|
lX2 = pContext->sClipRegion.sXMax - lX;
|
|
}
|
|
else
|
|
{
|
|
lX2 = lWidth - 1;
|
|
}
|
|
|
|
//
|
|
// Reduce the height of the image, if required, based on the current
|
|
// clipping region.
|
|
//
|
|
if((lY + lHeight - 1) > pContext->sClipRegion.sYMax)
|
|
{
|
|
lHeight = pContext->sClipRegion.sYMax - lY + 1;
|
|
}
|
|
|
|
//
|
|
// The image palette is in 24 bit R-G-B format. The palette needs
|
|
// to be translated into the color format accepted by the LCD
|
|
// and stored in g_pulConvertedPalette[] buffer
|
|
//
|
|
pucPalette = GrPaletteConversion(pContext, pBitmap);
|
|
pucImage = pBitmap->pPixel;
|
|
|
|
//
|
|
// Check if the image is not compressed.
|
|
//
|
|
if(!(lBPP & 0xF0))
|
|
{
|
|
//
|
|
// The image is not compressed. See if the top portion of the image
|
|
// lies above the clipping region.
|
|
//
|
|
if(lY < pContext->sClipRegion.sYMin)
|
|
{
|
|
//
|
|
// Determine the number of rows that lie above the clipping region.
|
|
//
|
|
lX1 = pContext->sClipRegion.sYMin - lY;
|
|
|
|
//
|
|
// Skip past the data for the rows that lie above the clipping
|
|
// region.
|
|
//
|
|
pucImage += (((lWidth * lBPP) + 7) / 8) * lX1;
|
|
|
|
//
|
|
// Decrement the image height by the number of skipped rows.
|
|
//
|
|
lHeight -= lX1;
|
|
|
|
//
|
|
// Increment the starting Y coordinate by the number of skipped
|
|
// rows.
|
|
//
|
|
lY += lX1;
|
|
}
|
|
|
|
while(lHeight--)
|
|
{
|
|
//
|
|
// Draw this row of image pixels.
|
|
//
|
|
DpyPixelDrawMultiple(pContext->pDisplay, lX + lX0, lY, lX0 & 7,
|
|
lX2 - lX0 + 1, lBPP,
|
|
pucImage + ((lX0 * lBPP) / 8), pucPalette);
|
|
|
|
//
|
|
// Skip past the data for this row.
|
|
//
|
|
pucImage += ((lWidth * lBPP) + 7) / 8;
|
|
|
|
//
|
|
// Increment the Y coordinate.
|
|
//
|
|
lY++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The image is compressed with RLE4 or RLE8 Algorithm
|
|
//
|
|
|
|
const unsigned char *pucData = pucImage;
|
|
unsigned char ucRunLength, ucTempRun;
|
|
unsigned char ucNoOverrun = 1;
|
|
unsigned int uiColor;
|
|
unsigned int uiLineCnt = 0;
|
|
unsigned int lXS = lX;
|
|
|
|
lBPP &= 0x0F;
|
|
|
|
while(lHeight--)
|
|
{
|
|
//
|
|
// Draw this row of image pixels.
|
|
//
|
|
while(uiLineCnt < lWidth)
|
|
{
|
|
if(ucNoOverrun) // Read next byte
|
|
{
|
|
if(lBPP == 8) // RLE 8 bit encoding
|
|
{
|
|
// Read Run Length
|
|
ucRunLength = *pucData++;
|
|
// Read Color Pointer
|
|
uiColor = *pucData++;
|
|
}
|
|
else // lBPP = 4; RLE 4 bit encoding
|
|
{
|
|
|
|
// Read Run Length
|
|
ucRunLength = (*pucData) >> 4;
|
|
// Read Color Pointer
|
|
uiColor = (*pucData++) & 0x0F;
|
|
}
|
|
uiColor = (*(unsigned int *)(pucPalette + uiColor));
|
|
|
|
}
|
|
else
|
|
{
|
|
//Last line run overran the edge
|
|
//Skip color and run length update and clear overrun flag
|
|
ucNoOverrun = 1;
|
|
ucRunLength = ucTempRun;
|
|
}
|
|
|
|
//After original value, but it still needs to be written once
|
|
if((ucRunLength + uiLineCnt) >= lWidth)
|
|
{
|
|
//Run length runs past current line
|
|
|
|
//Set left over run length for next line to ucTempRun
|
|
ucTempRun = ucRunLength - (lWidth - uiLineCnt);
|
|
//Set ucRunLength to finish this line
|
|
ucRunLength = (lWidth - uiLineCnt);
|
|
//Set line overrun flag
|
|
ucNoOverrun = 0;
|
|
}
|
|
|
|
//Draw single pixel
|
|
DpyPixelDraw(pContext->pDisplay, lX, lY, uiColor);
|
|
lX++;
|
|
|
|
uiLineCnt++;
|
|
|
|
while(ucRunLength--)
|
|
{
|
|
//Draw run of pixels
|
|
DpyPixelDraw(pContext->pDisplay, lX, lY, uiColor);
|
|
|
|
lX++;
|
|
|
|
uiLineCnt++;
|
|
}
|
|
}
|
|
//End of line reached
|
|
uiLineCnt = 0; //Reset Pixel Count
|
|
lY++; //Increment Y value
|
|
lX = lXS;
|
|
}
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Close the Doxygen group.
|
|
//! @}
|
|
//
|
|
//*****************************************************************************
|