Пример #1
0
/**
  * Pastes a given bitmap at the given co-ordinates.
  *
  * Any pixels in the relevant area of this image are replaced.
  *
  * @param image The MicroBitImage to paste.
  *
  * @param x The leftmost X co-ordinate in this image where the given image should be pasted. Defaults to 0.
  *
  * @param y The uppermost Y co-ordinate in this image where the given image should be pasted. Defaults to 0.
  *
  * @param alpha set to 1 if transparency clear pixels in given image should be treated as transparent. Set to 0 otherwise.  Defaults to 0.
  *
  * @return The number of pixels written.
  *
  * @code
  * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
  * MicroBitImage i(10,5,heart); // a big heart
  * i.paste(i, -5, 0); // a small heart
  * @endcode
  */
int MicroBitImage::paste(const MicroBitImage &image, int16_t x, int16_t y, uint8_t alpha)
{
    uint8_t *pIn, *pOut;
    int cx, cy;
    int pxWritten = 0;

    // Sanity check.
    // We permit writes that overlap us, but ones that are clearly out of scope we can filter early.
    if (x >= getWidth() || y >= getHeight() || x+image.getWidth() <= 0 || y+image.getHeight() <= 0)
        return 0;

    //Calculate the number of byte we need to copy in each dimension.
    cx = x < 0 ? min(image.getWidth() + x, getWidth()) : min(image.getWidth(), getWidth() - x);
    cy = y < 0 ? min(image.getHeight() + y, getHeight()) : min(image.getHeight(), getHeight() - y);

    // Calculate sane start pointer.
    pIn = image.ptr->data;
    pIn += (x < 0) ? -x : 0;
    pIn += (y < 0) ? -image.getWidth()*y : 0;

    pOut = getBitmap();
    pOut += (x > 0) ? x : 0;
    pOut += (y > 0) ? getWidth()*y : 0;

    // Copy the image, stride by stride
    // If we want primitive transparecy, we do this byte by byte.
    // If we don't, use a more efficient block memory copy instead. Every little helps!

    if (alpha)
    {
        for (int i=0; i<cy; i++)
        {
            for (int j=0; j<cx; j++)
            {
                // Copy this byte if appropriate.
                if (*(pIn+j) != 0){
                    *(pOut+j) = *(pIn+j);
                    pxWritten++;
                }
            }

            pIn += image.getWidth();
            pOut += getWidth();
        }
    }
    else
    {
        for (int i=0; i<cy; i++)
        {
            memcpy(pOut, pIn, cx);

            pxWritten += cx;
            pIn += image.getWidth();
            pOut += getWidth();
        }
    }

    return pxWritten;
}
Пример #2
0
/**
  * Scrolls the given image across the display, from right to left.
  * Returns immediately, and executes the animation asynchronously.
  *
  * @param image The image to display.
  *
  * @param delay The time between updates, in milliseconds. Defaults
  *              to: MICROBIT_DEFAULT_SCROLL_SPEED.
  *
  * @param stride The number of pixels to shift by in each update. Defaults to MICROBIT_DEFAULT_SCROLL_STRIDE.
  *
  * @return MICROBIT_OK, MICROBIT_BUSY if the display is already in use, or MICROBIT_INVALID_PARAMETER.
  *
  * @code
  * MicrobitImage i("1,1,1,1,1\n1,1,1,1,1\n");
  * display.scrollAsync(i,100,1);
  * @endcode
  */
int MicroBitDisplay::scrollAsync(MicroBitImage image, int delay, int stride)
{
    //sanitise the delay value
    if(delay <= 0)
        return MICROBIT_INVALID_PARAMETER;

    // If the display is free, it's our turn to display.
    if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
    {
        scrollingImagePosition = stride < 0 ? width : -image.getWidth();
        scrollingImageStride = stride;
        scrollingImage = image;
        scrollingImageRendered = false;

        animationDelay = stride == 0 ? 0 : delay;
        animationTick = 0;
        animationMode = ANIMATION_MODE_SCROLL_IMAGE;
    }
    else
    {
        return MICROBIT_BUSY;
    }

    return MICROBIT_OK;
}