These are chat archives for Makuna/NeoPixelBus

19th
Mar 2016
Michael Miller
@Makuna
Mar 19 2016 00:49
@3DSasha 100 leds should be fine, it wont be about updating that few pixels it will be more about cpu to calculate the animations/copy frame buffers/or what ever is driving your effects. The Esp8266 (all but a few like the esp01) has the benefit that its default update method under the hood is by DMA hardware. It takes more memory, but it provides a back buffer that is being sent by hardware while you are calculating and updating the next frame.; so its much faster.
@codmpm do you have link to the specific board?
Also note that by default the esp8266 can only use one pin, it ignores the pin you pass. this is due to the DMA hardware support only works on one pin. GPIO3, which ever pin that is exposed on your board (how its labeled sometimes is strange, like with the esp-12e, GPIO03 is D9.
sticilface
@sticilface
Mar 19 2016 01:41
but I am actively working on matrix support and texture support.
ooo....
sticilface
@sticilface
Mar 19 2016 02:02
what matrix support are you planning. I modified the adafruitGFX lib providing a callback for pixel location based on the lib config. It works pretty well. I can provide an example if you wish... but i thought that there is no need to re-invent the wheel. what are you planning, can i be of assistance?
Michael Miller
@Makuna
Mar 19 2016 02:11

@sticilface how it works is that it just converts a 2d coordinate to a pixel index, so you instance the converter like...

Topology<ColumnMajorAlternatingLayout> topo(PanelWidth, PanelHeight);

and then when you want to set a pixel at a x,y location, you do something like...

strip.SetPixelColor(topo.Map(6,8), red);
sticilface
@sticilface
Mar 19 2016 02:14
mmm
i've spent quite a while with the matrixGFX implementing it... how about fonts...
GFX supports font drawing etc..
Michael Miller
@Makuna
Mar 19 2016 02:15

If you have a collection of panels, then I have a mosaic and tile classes that can be instanced, mosaic has requirements on how you layout the tiles, but it keeps the interconnections the shortest they can be using one panel layout type, like....

Mosaic <RowMajorLayout> mosaic(
    PanelWidth, 
    PanelHeight, 
    TileWidth, 
    TileHeight);

and use it like...

strip.SetPixelColor(mosaic.Map(32,64), green);
sticilface
@sticilface
Mar 19 2016 02:15
oh, this sounds pretty interesting
Michael Miller
@Makuna
Mar 19 2016 02:16
I want to look into the GFX library and see how it can be used with my library so I don't have to reinvent that work.
I have this working now, but I am writing samples for it and need to investigate a few things for when I write the Wiki stuff for it.
sticilface
@sticilface
Mar 19 2016 02:19
well i've copied the matrix lib, which inherits the GFX lib.. basically... it calls down to draw pixel.. kind of like print does with write... i then replaced that will a callback.. which you can put in your animation call back... the result is that you can draw all the shapes and use the gfx lib natively with neopixels... i've got a text marquee working, and all sorts of shape drawing stuff...
class Melvtrix: public Adafruit_GFX
{

public:
  // Constructor for single matrix:
  Melvtrix(int w, int h,
           uint8_t matrixType = NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS);

  // Constructor for tiled matrices:
  Melvtrix(uint8_t matrixW, uint8_t matrixH, uint8_t tX,
           uint8_t tY,
           uint8_t matrixType = NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS +
                                NEO_TILE_TOP + NEO_TILE_LEFT + NEO_TILE_ROWS);

  void drawPixel(int16_t x, int16_t y, uint16_t color); // colour is ignored here.. handle it in the actual function...
  void drawPixel(int16_t x, int16_t y) { drawPixel(x, y, 0); }
  int  getPixel(uint16_t x, uint16_t y);

  void setShapeFn(ShapeUpdateCallback Fn);
private:

  const uint8_t
  type;
  const uint8_t
  matrixWidth, matrixHeight, tilesX, tilesY;
  ShapeUpdateCallback ShapeFn;

};
this is the basic class...
Michael Miller
@Makuna
Mar 19 2016 02:21
The texture work is still in progress, its basically a container for an image (or you can think of it as a 2d collection of colors) and then you can say draw from it to the matrix classes and it will interpolate the values in.
I thought there Gfx library worked with LCD panels also, so it had a mechanism to let you plug in your device update.
sticilface
@sticilface
Mar 19 2016 02:27
yeah the GFX allows you to draw shapes and fonts, the matrix lib allows you to translate that into a 'string' of leds. which is not how most LED displays work. they are not in series..
to work out where they all are.. kind of like where you are at with the matrix stuff.. but then they have the shapes stuff
Michael Miller
@Makuna
Mar 19 2016 02:30
I just looked at their Gfx, library, its actual support for NeoPixels is pretty bad, the color it takes is only 16 bits. NeoPixels take 24 bits. That sucks!
sticilface
@sticilface
Mar 19 2016 02:31
thats why i took out colour...
it only handles the pixel placement... your lib takes care of everything else
Michael Miller
@Makuna
Mar 19 2016 02:32
I hate the way they design their classes. Its so 1990s C++, to many virtuals.
sticilface
@sticilface
Mar 19 2016 02:33
hahah
there are a lot... but then there was a lot of clever stuff under the hood that i could / did not have the time to understand / copy
like shapes, and fonts
Michael Miller
@Makuna
Mar 19 2016 02:35
and they use "text book" coding styles that any company would not accept for a checkin. Makes it hard to read.
sticilface
@sticilface
Mar 19 2016 02:37
if they overuse virtual.... then i overuse callbacks
i've kind of got 3 or more going on for an effect...
Michael Miller
@Makuna
Mar 19 2016 02:40
not sure you have looked at the template style I use, its a way of providing functionality without using virtuals or callbacks, and basically compiles down pretty small. It doesn't solve every problem and sometimes you will still need a callback, buts its rare you need a virtual.
sticilface
@sticilface
Mar 19 2016 02:41
i've kind of copied the 'handler' classes of web server for a lot of things... including using a handler of a template virtual...
it works pretty well... not had any issues with it. is there a reason to avoid? apart from the extra call or two to look it up from the vtable?
Michael Miller
@Makuna
Mar 19 2016 02:43
vtable costs are not always obvious, derive from a derived class and things can get pretty ugly with the vtable. While larger CPUs have have indirect function calls in assemble that handle the vtable calls without extra cost, these small CPUs do not.
And you can't always get away from them, so take my words with a grain of salt.
sticilface
@sticilface
Mar 19 2016 02:45
so the ESP does not have that the?
so this code... draws random or specific shapes (or just lines if matrix is disabled), that are non-overlapping, with colours from a palette class... size, shape, speed, color, number of effects are all set from a web GUI

bool Blobs::Start()
{
    strip->ClearTo(0);

    if (matrixMan()) {
        if (usematrix()) {
            matrixMan()->enable();
        } else {
            matrixMan()->disable();
        }
    }

    if (animator) {
        delete animator;
        animator = nullptr;
    }

    animator = new NeoPixelAnimator(effectnumber());

    if (_vars->manager) {
        delete _vars->manager;
    }

    _vars->manager = new EffectGroup;

    for (uint8_t i = 0; i < effectnumber(); i++) {
        _vars->manager->Add(i, 100 , new SimpleEffectObject()); // if its 2d then no need to hold so many pixels
    }

    setshape( shapemode() );

    for (uint8_t obj = 0; obj < effectnumber(); obj++) {

        SimpleEffectObject * current =  static_cast<SimpleEffectObject*>(_vars->manager->Get(obj));  // cast handler to the Blobs class...

        if (!current) { break; }

        current->SetObjectUpdateCallback( [ current, this ]() {

            uint16_t pixel_count = 0;

            //  count the number of pixels... not sure of a better way to get this from adafruit lib...
            if (matrix()) {

                setshape(shapemode());

                if (size() * 2 < matrix()->width() || size() * 2 < matrix()->height() ) {
                    current->x = random(0, matrix()->width() - size() + 1);
                    current->y = random(0, matrix()->height() - size() + 1);
                } else {
                    current->x = random(0, matrix()->width() );
                    current->y = random(0, matrix()->height() );
                }

                current->size = size();

                matrix()->setShapeFn( [ &pixel_count ] (uint16_t pixel, int16_t x, int16_t y) {
                    pixel_count++;
                });

                shape(current);
                current->create(pixel_count);
                pixel_count = 0;

                matrix()->setShapeFn( [ current, &pixel_count ] (uint16_t pixel, int16_t x, int16_t y) {
                    if (current->pixels()) {
                        current->pixels()[pixel_count++] = pixel;
                    }
                });

                shape(current);

            } else {
                //  linear points creation
                //  This kicks in if the Matrix is disabled to give simple linear effects...
                current->create(size());
                current->x = random(0, strip->PixelCount() - size() + 1);

                for (uint16_t pixel = 0; pixel < size(); pixel++) {
                    current->pixels()[pixel] = current->x + pixel;
                }

            }

            // pixels chosen check not in use by another animator...

            for (uint16_t i = 0; i < current->total(); i++) {
                if (_vars->manager->Inuse(current,  current->pixels()[i] ) ) {
                    return false;
                }
            }

            if (!current->pixels()) { return false ; } //  break if there are no pixels to draw.

            RgbColor targetColor = palette()->next();

            AnimUpdateCallback animUpdate = [ targetColor, current, this ](const AnimationParam & param) {
                // progress will start at 0.0 and end at 1.0
                // we convert to the curve we want
                float progress = param.progress;

                RgbColor updatedColor;

                if (progress < 0.5) {
                    updatedColor = RgbColor::LinearBlend(0, targetColor, progress * 2.0f);
                } else {
                    updatedColor = RgbColor::LinearBlend(targetColor, 0, (progress - 0.5f) * 2.0f);
                }

                if (current->pixels()) {
                    for (uint16_t i = 0; i < current->total(); i++) {
                        strip->SetPixelColor( current->pixels()[i] , dim(updatedColor, brightness()));
                    }
                }
                ///  maybe need to delete pixels() at end of the effect here...
                //  to remove it from the in use....

                if (param.state == AnimationState_Completed) {
                    current->end();
                }

            };

            // now use the animation properties we just calculated and start the animation
            // which will continue to run and call the update function until it completes

            uint32_t lower = map( speed(), 0, 255, 100, 10000 );
            uint32_t upper = map( speed(), 0, 255, lower, lower + 10000 );

            uint32_t timefor = random(lower, upper );

            current->Timeout(timefor);

            animator->StartAnimation(current->id(), timefor - 50 , animUpdate);
            return true;

        });

    }

}

bool Blobs::Run()
{
    if (_vars) {
        if (_vars->manager) {
            _vars->manager->Update();
        }
    }
}
https://www.dropbox.com/s/al2dgcbskei5isz/Screenshot%202016-03-19%2002.45.00.png?dl=0
its fairly... complicated... but essentially... Start sets everything up, defines the callback.. in which the next position is chosen, and an object is created of the right size to hold all the pixels... then is it checked to see if it overlaps, if not then it is drawn...
dropbox link is the gui
Michael Miller
@Makuna
Mar 19 2016 02:50
So the palette object just contains colors? single row?
sticilface
@sticilface
Mar 19 2016 02:51
no.. palette is a bit of a monster...
with an easy input output
allows you to set color themes... complimentary... time based looping, count based looping...
but effects can just ask for the 'next' color and it will serve it up
you can have many different palette settings
    static RgbColor comlementary(RgbColor input, uint16_t position);
    static RgbColor monochromatic(RgbColor input, uint16_t position);
    static RgbColor analogous(RgbColor input, uint16_t position, uint16_t total, float range);
    static RgbColor splitcomplements(RgbColor input, uint16_t position, float range);
    static RgbColor triadic(RgbColor input, uint16_t position) // return multiple (total set to 3)
+
    static RgbColor triadic(RgbColor input, uint16_t position) // return multiple (total set to 3)
    {
        return multi(input, position, 3);
    }
    static RgbColor tetradic(RgbColor input, uint16_t position) // return multiple set to 4.. might tweak this a bit..
    {
        return multi(input, position, 4);
    }
    static RgbColor multi(RgbColor input, uint16_t position, uint16_t total) ;
    static RgbColor wheel(uint8_t position);
Michael Miller
@Makuna
Mar 19 2016 02:53
strange concept, never ran into anything like that before. I come from a game dev background, it seems to be a mix of a texture and shader in one.
sticilface
@sticilface
Mar 19 2016 02:53
means you can create blends... or generate colours
that are sufficiently different from each other to be 'interesting'
i wrote the whole thing.. and have 0 background in anything... so just developed it to work for my lamps:)
I'm trying to upload a video to kind of show it.. but its not working...
Michael Miller
@Makuna
Mar 19 2016 02:55
a texture is a 2d collection of colors (often RGBA) that a shader (piece of code like what you have in a animation callback) will use to create those interesting things in the most efficient way.
sticilface
@sticilface
Mar 19 2016 02:55
ah ok...
here is the whole thing
Michael Miller
@Makuna
Mar 19 2016 02:56
Sometimes shaders use the texture like palette (single row tall), sometimes they use it like an image.
sticilface
@sticilface
Mar 19 2016 02:56
this is quite old.. i have to go back and really get it to work...
i figured with the esp it was easier to calculate everything.. rather than have 'stored' arrays of colours that use ram
Michael Miller
@Makuna
Mar 19 2016 02:57
in general this is true, but if you have an artist friend providing assets for your work, they often think in bitmaps ;-)
sticilface
@sticilface
Mar 19 2016 03:00
yes... and i've thought of 2 things along those lines... i think the gfx lib support bitmaps... and how to include that... and maybe have either patterns stored in files i.e. sequences.. or patterns as you suggest... all coming from SPIFFS.. got a lot on my plate with this stuff... i spent most of my time writing some easy way to have different variable stored for different effects, and then have them sent to the web guy in json... figured it out though and it works well now.. its as easy as 3-4 lines of code to add a parameter to an effect, and have it saveable, and sent to the web front end..
anyways.. I'm off to bed it 3am here...
i'd be curious to learn more about shader and texture stuff... seeing as i know 0.
Michael Miller
@Makuna
Mar 19 2016 03:04
goodnight, time for me to shut the computer down too.