TLIGHT_PRODUCTS / WS281X

PixelBuffer.cpp

Committer:
mutech
Date:
2016-11-04
Revision:
35:dffa06d09fdc
Parent:
34:5a141ed5d52a
Child:
36:0fe7917a832a

File content as of revision 35:dffa06d09fdc:

/* PixelBuffer.cpp
 * mbed Microcontroller Library
 * Copyright (c) 2016 muetch, t.kuroki
 * Allrights reserved.
 *
 * Rev 0.97 2016-09-07
 * Rev 0.98 2016-09-08
 */
#include "PixelBuffer.h"

#define USE_MALLOC          1   // 0:new, 1:malloc

//----------------------------------------------------------------------------
// 指定されたバッファの先頭からblock_size分をbuf_sizeが満杯になるまで繰り返しコピーする
template <class T>
static void repeat_buffer(T *buffer, int buf_size, int block_size = 1)
{
    if (buffer && block_size > 0 && (uint16_t)block_size < buf_size)
    {
        T *dest = buffer + block_size;
        int left = buf_size - block_size;
        while (left > block_size)
        {
            memcpy(dest, buffer, block_size * sizeof(T));
            dest += block_size;
            left -= block_size;
            block_size <<= 1;       // 次回は2倍のサイズの転送
        }
        memcpy(dest, buffer, left * sizeof(T));
    }
}

//----------------------------------------------------------------------------
RGBPixels::RGBPixels(RGBColor *buffer, int maxPixels)
    : _owned_buffer(false)
{
    _dummyPixel = 0;
    setPixelBuffer(buffer, maxPixels);
}

RGBPixels::RGBPixels(int maxPixels)
    : _owned_buffer(false)
{
    _dummyPixel = 0;
    setPixelBuffer(nullptr, maxPixels);
}

RGBPixels::~RGBPixels()
{
    setPixelBuffer(0, 0);
}

void RGBPixels::setPixelBuffer(RGBColor *buffer, int maxPixels)
{
    if (_owned_buffer && _pixels)
    {
#if USE_MALLOC
        free(_pixels);
#else
        delete[] _pixels;
#endif
    }
    _owned_buffer = false;
    _maxPixels = (maxPixels < 0) ? 0 : (maxPixels > MAX_PIXELS) ? MAX_PIXELS : maxPixels;
    _pixels = (!_maxPixels) ? NULL : buffer;

    if (!_pixels && _maxPixels > 0)
    {
#if USE_MALLOC
        _pixels = static_cast<RGBColor*>(malloc(sizeof(RGBColor)*_maxPixels));
        if (_pixels)
            _owned_buffer = true;
        else
            _maxPixels = 0;
#else
        _pixels = new RGBColor[_maxPixels];
        _owned_buffer = true;
#endif
    }
    _numPixels = _maxPixels;
    clear();
}

int RGBPixels::numPixels(int value)
{
    if (value >= 0)
        _numPixels = (value > _maxPixels) ? _maxPixels : value;
    return _numPixels;
}

// 指定位置のピクセルへ色配列を指定サイズ分をコピーする
void RGBPixels::setPixels(int index, RGBColor *color, int len)
{
    int numPixels = static_cast<int>(_numPixels);
    if (_pixels && len > 0 && index < numPixels && (index + len) >= 0)
    {
        if (index < 0)
		{
			len   += index;
			color -= index;
			index  = 0;
		}
        if (index + len > numPixels)
            len = numPixels - index;
        memcpy(&_pixels[index], color, len * sizeof(_pixels[0]));
    }
}

void RGBPixels::setPixels(int index, HSVColor *color, int len)
{
    int numPixels = static_cast<int>(_numPixels);
    if (_pixels && len > 0 && index < numPixels && (index + len) >= 0)
    {
        if (index < 0)
		{
			len   += index;
			color -= index;
			index  = 0;
		}
        if (index + len > numPixels)
            len = numPixels - index;
        RGBColor *dest = &_pixels[index];
        do
        {
            *dest++ = *color++;
        } while (--len);
    }
}

// 指定色を指定位置のピクセルから指定サイズ分書き込む
void RGBPixels::fillPixels(int index, const RGBColor color, int len)
{
    if (_pixels && len > 0 && (uint16_t)index < _numPixels)
    {
        if (index + len > _numPixels)
            len = _numPixels - index;
        _pixels[index] = color;
        repeat_buffer<RGBColor>(_pixels + index, len, 1);
    }
}

void RGBPixels::fillPixels(int index, const HSVColor color, int len)
{
    fillPixels(index, RGBColor(color), len);
}

// 先頭から指定サイズ分のブロックをバッファの最後までコピーする
void RGBPixels::repeatPixels(int block_size)
{
    if (_pixels && block_size > 0 && block_size < _numPixels)
    {
        repeat_buffer<RGBColor>(_pixels, _numPixels, block_size);
    }
}

void RGBPixels::repeatPixels(RGBColor *source, int size)
{
    if (_pixels && source && size > 0)
    {
        if (size > _numPixels)
            size = _numPixels;
        memcpy(_pixels, source, size * sizeof(_pixels[0]));
        repeat_buffer<RGBColor>(_pixels, _numPixels, size);
    }
}

void RGBPixels::repeatPixels(HSVColor *source, int size)
{
    if (_pixels && source && size > 0)
    {
        if (size > _numPixels)
            size = _numPixels;
        for (int i = 0; i < size; ++i)
            _pixels[i] = *source++;
        repeat_buffer<RGBColor>(_pixels, _numPixels, size);
    }
}

RGBPixels& RGBPixels::operator=(const RGBPixels& rhs)
{
    if (!rhs._pixels || !rhs._maxPixels)
    {
        // 右辺が空の場合何もしない
        return *this;
    }
    if (!_pixels || !_maxPixels)
    {
        // 自分のバッファなしの場合、、新規確保
        setPixelBuffer(nullptr, rhs._maxPixels);
    }

    if (_pixels && _maxPixels)
    {
        _numPixels = rhs._numPixels;
        if (_numPixels > rhs._maxPixels)
            _numPixels = rhs._maxPixels;
        if (_numPixels > _maxPixels)
            _numPixels = _maxPixels;
        memcpy(_pixels, rhs._pixels, sizeof(_pixels[0]) * _numPixels);
    }

    return *this;
}

//----------------------------------------------------------------------------
void RGBPixels::makeGradation(int index, RGBColor from, RGBColor to, int len)
{
    if (!_pixels || len < 1 || index >= _numPixels || (index + len) < 0)
        return;

    int end = len;
    if (index + end > _numPixels)
        end = _numPixels - index;

    RGBColor color;
    RGBColor *dest = _pixels;
    if (index > 0)
        dest += index;
    for (int i = (index < 0) ? -index : 0; i < end; ++i)
    {
        int j = len - i;
        color.red   = ((from.red   * j) + (to.red   * i)) / len;
        color.green = ((from.green * j) + (to.green * i)) / len;
        color.blue  = ((from.blue  * j) + (to.blue  * i)) / len;
        *dest++     = GammaColor(color);
    }
}

void RGBPixels::makeRainbow(int index, HSVColor color, int len, int direction)
{
    if (!_pixels || len < 1 || index >= _numPixels || (index + len) < 0)
        return;

    int end = len;
    if (index + end > _numPixels)
        end = _numPixels - index;

    HSVColor hsv(color);
    RGBColor *dest = _pixels;
    if (index > 0)
        dest += index;
    direction = (direction >= 0) ? -3600 : 3600;
    for (int i = (index < 0) ? -index : 0; i < end; ++i)
    {
        hsv.hue = color.hue + direction * i / len;
        *dest++ = GammaColor(hsv);
    }
}

//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
HSVPixels::HSVPixels(HSVColor *buffer, int maxPixels)
    : _owned_buffer(false)
{
    _dummyPixel = 0;
    setPixelBuffer(buffer, maxPixels);
}

HSVPixels::HSVPixels(int maxPixels)
    : _owned_buffer(false)
{
    _dummyPixel = 0;
    setPixelBuffer(nullptr, maxPixels);
}

HSVPixels::~HSVPixels()
{
    setPixelBuffer(0, 0);
}

void HSVPixels::setPixelBuffer(HSVColor *buffer, int maxPixels)
{
    if (_owned_buffer && _pixels)
    {
#if USE_MALLOC
        free(_pixels);
#else
        delete[] _pixels;
#endif
    }
    _owned_buffer = false;
    _maxPixels = (maxPixels < 0) ? 0 : (maxPixels > MAX_PIXELS) ? MAX_PIXELS : maxPixels;
    _pixels = (!_maxPixels) ? NULL : buffer;

    if (!_pixels && _maxPixels > 0)
    {
#if USE_MALLOC
        _pixels = static_cast<HSVColor*>(malloc(sizeof(HSVColor)*_maxPixels));
        if (_pixels)
            _owned_buffer = true;
        else
            _maxPixels = 0;
#else
        _pixels = new HSVColor[_maxPixels];
        _owned_buffer = true;
#endif
    }
    _numPixels = _maxPixels;
    clear();
}

int HSVPixels::numPixels(int value)
{
    if (value >= 0)
        _numPixels = (value > _maxPixels) ? _maxPixels : value;
    return _numPixels;
}

// 指定位置のピクセルへ色配列を指定サイズ分をコピーする
void HSVPixels::setPixels(int index, HSVColor *color, int len)
{
    int numPixels = static_cast<int>(_numPixels);
    if (_pixels && len > 0 && index < numPixels && (index + len) >= 0)
    {
        if (index < 0)
		{
			len   += index;
			color -= index;
			index  = 0;
		}
        if (index + len > numPixels)
            len = numPixels - index;
        memcpy(&_pixels[index], color, len * sizeof(_pixels[0]));
    }
}

void HSVPixels::setPixels(int index, RGBColor *color, int len)
{
    int numPixels = static_cast<int>(_numPixels);
    if (_pixels && len > 0 && index < numPixels && (index + len) >= 0)
    {
        if (index < 0)
		{
			len   += index;
			color -= index;
			index  = 0;
		}
        if (index + len > numPixels)
            len = numPixels - index;
        HSVColor *dest = &_pixels[index];
        do
        {
            *dest++ = *color++;
        } while (--len);
    }
}

// 指定色を指定位置のピクセルから指定サイズ分書き込む
void HSVPixels::fillPixels(int index, const HSVColor color, int len)
{
    if (_pixels && len > 0 && (uint16_t)index < _numPixels)
    {
        if (index + len > _numPixels)
            len = _numPixels - index;
        _pixels[index] = color;
        repeat_buffer<HSVColor>(_pixels + index, len, 1);
    }
}

void HSVPixels::fillPixels(int index, const RGBColor color, int len)
{
    fillPixels(index, HSVColor(color), len);
}

// 先頭から指定サイズ分のブロックをバッファの最後までコピーする
void HSVPixels::repeatPixels(int block_size)
{
    if (_pixels && block_size > 0 && block_size < _numPixels)
    {
        repeat_buffer<HSVColor>(_pixels, _numPixels, block_size);
    }
}

void HSVPixels::repeatPixels(HSVColor *source, int size)
{
    if (_pixels && source && size > 0)
    {
        if (size > _numPixels)
            size = _numPixels;
        memcpy(_pixels, source, size * sizeof(_pixels[0]));
        repeat_buffer<HSVColor>(_pixels, _numPixels, size);
    }
}

void HSVPixels::repeatPixels(RGBColor *source, int size)
{
    if (_pixels && source && size > 0)
    {
        if (size > _numPixels)
            size = _numPixels;
        for (int i = 0; i < size; ++i)
            _pixels[i] = *source++;
        repeat_buffer<HSVColor>(_pixels, _numPixels, size);
    }
}

HSVPixels& HSVPixels::operator=(const HSVPixels& rhs)
{
    if (!rhs._pixels || !rhs._maxPixels)
    {
        // 右辺が空の場合何もしない
        return *this;
    }
    if (!_pixels || !_maxPixels)
    {
        // 自分のバッファなしの場合、、新規確保
        setPixelBuffer(nullptr, rhs._maxPixels);
    }

    if (_pixels && _maxPixels)
    {
        _numPixels = rhs._numPixels;
        if (_numPixels > rhs._maxPixels)
            _numPixels = rhs._maxPixels;
        if (_numPixels > _maxPixels)
            _numPixels = _maxPixels;
        memcpy(_pixels, rhs._pixels, sizeof(_pixels[0]) * _numPixels);
    }

    return *this;
}

//----------------------------------------------------------------------------
void HSVPixels::makeGradation(int index, HSVColor from, HSVColor to, int len)
{
    if (!_pixels || len < 1 || index >= _numPixels || (index + len) < 0)
        return;

    int end = len;
    if (index + end > _numPixels)
        end = _numPixels - index;

    RGBColor rgb_from(from);
    RGBColor rgb_to(to);
    RGBColor color;
    HSVColor *dest = _pixels;
    if (index > 0)
        dest += index;
    for (int i = (index < 0) ? -index : 0; i < end; ++i)
    {
        int j = len - i;
        color.red   = ((rgb_from.red   * j) + (rgb_to.red   * i)) / len;
        color.green = ((rgb_from.green * j) + (rgb_to.green * i)) / len;
        color.blue  = ((rgb_from.blue  * j) + (rgb_to.blue  * i)) / len;
        *dest++     = GammaColor(color);
    }
}

void HSVPixels::makeRainbow(int index, HSVColor color, int len, int direction)
{
    if (!_pixels || len < 1 || index >= _numPixels || (index + len) < 0)
        return;

    int end = len;
    if (index + end > _numPixels)
        end = _numPixels - index;

    HSVColor hsv(color);
    HSVColor *dest = _pixels;
    if (index > 0)
        dest += index;
    direction = (direction >= 0) ? -3600 : 3600;
    for (int i = (index < 0) ? -index : 0; i < end; ++i)
    {
        hsv.hue = color.hue + direction * i / len;
       *dest++ = GammaColor(hsv);
    }
}

//----------------------------------------------------------------------------