hzeller / rpi-rgb-led-matrix

Controlling up to three chains of 64x64, 32x32, 16x32 or similar RGB LED displays using Raspberry Pi GPIO
GNU General Public License v2.0
3.67k stars 1.17k forks source link

fade in / Fade out in image scroller #131

Closed ts4pi closed 8 years ago

ts4pi commented 8 years ago

Hi, is it possible to change brightness in Imagescroller while running ? I would like to have a fade in / fade out or blinking Best regards Thomas

hzeller commented 8 years ago

You have to implement that yourself, but should be a nice small exercise. There is a SetBrightness() call that takes values from 0..100 (essentially percent).

Note that setting the brigthness requires to set all the pixels again, but if you scroll the image, that happens anyway.

soyxan commented 7 years ago

I want to do this fade in and fade out with whatever is drawn on the Canvas (text, images, etc.) As you said I need to SetPixel again in order to get the new brightness. Instead of drawing the image again, I was wondering if I just can get the pixels color directly from the current canvas (¿¿GetPixel??), SetBrightness to a new Canvas, SetPixel to the new Canvas and then SwapOnVSync with the new Canvas.

hzeller commented 7 years ago

You can't get the current pixel color, as the RGBMatrix immediately translates it into the needed underlying bit-pattern (this makes it fast to display), but there is no translation-back implemented.

So if you want to do that, you might want to implement a Canvas interface that keeps a copy of the original pixel color on SetPixel() (storing in a 2-dimenstional array essentially), then delegates to some underlying Canvas (the FrameCanvas of the RGBMatrix). Then you can implement a method GetPixel() on your Canvas implementation that allows you to get the original color.

soyxan commented 7 years ago

Following your suggestion I've tried is to make a derived class of FrameCanvas that way:

class FrameCanvas2 : public FrameCanvas {
public:
    void SetPixel(int x, int y, uint8_t red, uint8_t green, uint8_t blue){
        printf("SetPixel");
        if (pixels_.size()==0) pixels_.resize(this->width(), vector<rgb_matrix::Color> (this->height(), rgb_matrix::Color(0,0,0)));
        pixels_[x][y].r = red;
        pixels_[x][y].g = green;
        pixels_[x][y].b = blue;
        FrameCanvas::SetPixel(x, y, red, green, blue);
    }
    void GetPixel(int x, int y, uint8_t * red, uint8_t * green, uint8_t * blue){
        *red = pixels_[x][y].r;
        *green = pixels_[x][y].g;
        *blue = pixels_[x][y].b;
    }
private:
    std::vector<std::vector<rgb_matrix::Color> > pixels_;
};

But my implementation of SetPixel is never called, being called the base class SetPixel instead (I have tested calling rgb_matrix::DrawText passing my Framecanvas2 implementation, and the text is drawn on the panels but my "printf" is never shown).

I am sure that there is a better way to do it, but I am not that "good" with C++, can you give me some directions? Thanks a lot!

hzeller commented 7 years ago

Don't derive, make a delegation instead. Then you can wrap the canvas coming from the RGBMatrix

On Apr 28, 2017 16:51, "soyxan" notifications@github.com wrote:

Following your suggestion I've tried is to make a derived class of FrameCanvas that way:

class FrameCanvas2 : public FrameCanvas { public: void SetPixel(int x, int y, uint8_t red, uint8_t green, uint8t blue){ printf("SetPixel"); if (pixels.size()==0) pixels_.resize(this->width(), vector (this->height(), rgbmatrix::Color(0,0,0))); pixels[x][y].r = red; pixels[x][y].g = green; pixels[x][y].b = blue; FrameCanvas::SetPixel(x, y, red, green, blue); } void GetPixel(int x, int y, uint8_t red, uint8_t green, uint8t blue){ red = pixels[x][y].r; green = pixels_[x][y].g; blue = pixels_[x][y].b; } private: std::vector<std::vector > pixels_; };

But my implementation fo SetPixel is never called, being called the base class SetPixel instead (I have tested calling rgb_matrix::DrawText with my Framecanvas2 implementation, and the text is drawn on the panels but my "printf" is never shown).

I am sure that there is a better way to do it, but I am not that "good" with C++, can you give me some directions? Thanks a lot!

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub https://github.com/hzeller/rpi-rgb-led-matrix/issues/131#issuecomment-298019291, or mute the thread https://github.com/notifications/unsubscribe-auth/AAImiRnYO0HSYEyf1ALUPWLAO6QDOHNZks5r0fzxgaJpZM4IOZNg .

soyxan commented 7 years ago

Do you mean something like that? (I get plenty of errors when compiling)

class FrameCanvas2 : public FrameCanvas {
public:
    FrameCanvas2(FrameCanvas *c) {
        framecanvas_ = c;
    }

    void SetPixel(int x, int y, uint8_t red, uint8_t green, uint8_t blue){
        printf("SetPixel");
        framecanvas_->SetPixel(x,y,red,green,blue)
    }
private:
    FrameCanvas* framecanvas_;
};
hzeller commented 7 years ago

FrameCanvas is a private implementation, you can't extend that. The overall interface is the Canvas, which you need to extend, roughtly like this:

class MyGetPixelCanvas : public rgb_matrix::Canvas {
public:
   MyGetPixelCanvas(FrameCanvas *canvas) : delegatee_(canvas) {}
   int width() const { return delegatee_->width(); }
   int height() const { return delegatee_->height(); }
   void SetBrightness(uint8_t b) { delegatee_->SetBrightness(b); }

    // etc., implement Clear(), Fill() as well by delegation

   void SetPixel(...) { /* your implementation storing away pixels, then */ delegatee_->SetPixel(...); }
   Color GetPixel(int x, int y) { /* your implementation */ }

private:
   FrameCanvas *const delegatee_;
};

Then you can wrap this canvas around a FrameCanvas:

MyGetPixelCanvas canvas(some_frame_canvas);
canvas.SetPixel(...)
canvas.SetBrightness(...);
canvas.GetPixel(...)
soyxan commented 7 years ago

I have implemented all the methods of Canvas class in my wrapper:

class FrameCanvas2 : public rgb_matrix::Canvas {
public:
    FrameCanvas2(rgb_matrix::Canvas *canvas) : delegatee_(canvas) {}
    int width() const { return delegatee_->width(); }
    int height() const { return delegatee_->height(); }
    void Fill(uint8_t red, uint8_t green, uint8_t blue) { delegatee_->Fill(red, green, blue);}
    void Clear() {delegatee_->Clear();}

    void SetPixel(int x, int y, uint8_t red, uint8_t green, uint8_t blue){
        printf("SetPixel");
        delegatee_->SetPixel(x,y,red,green,blue);
    }
    rgb_matrix::Color GetPixel(int x, int y)
    {

    }
private:
   Canvas *const delegatee_;
};

Now I will use it in my ThreadedCanvasManipulator implementation in order to draw some scrolling text:

class Texto : public ThreadedCanvasManipulator {
public:
    Texto(RGBMatrix *m, const char * texto) : ThreadedCanvasManipulator(m), matrix_(m), texto_(texto) {
        off_screen_canvas_ = new FrameCanvas2(m->CreateFrameCanvas());
    }
    void Run() {
        rgb_matrix::Color color(255, 255, 0);

        rgb_matrix::Font font;
        if (!font.LoadFont("/home/pi/matrix/fuentes/bebasneue.bdf")) {
            fprintf(stderr, "Couldn't load font");
            return;
        }
        int brightness = 100;

        off_screen_canvas_->SetBrightness(brightness);

        bool all_extreme_colors = brightness == 100;
        all_extreme_colors &= color.r == 0 || color.r == 255;
        all_extreme_colors &= color.g == 0 || color.g == 255;
        all_extreme_colors &= color.b == 0 || color.b == 255;
        if (all_extreme_colors)
        off_screen_canvas_->SetPWMBits(1);
        int x=off_screen_canvas_->width();
        int lentext=0;

        while (running() && !interrupt_received) {
            usleep(10 * 1000);
            off_screen_canvas_->Clear();
            lentext = rgb_matrix::DrawText(off_screen_canvas_, font, x, 0 + font.baseline(), color, texto_);
            off_screen_canvas_->SetPixel(10,10,255,0,0);
            /*off_screen_canvas_ = */matrix_->SwapOnVSync(off_screen_canvas_);
            x--;
            if (x<(-1*lentext)) x=off_screen_canvas_->width();
        }
    }

private:
    RGBMatrix *const matrix_;
    FrameCanvas2 *off_screen_canvas_;
    const char * texto_;
};

But the compiler says that it can't find matching function for off_screen_canvas->SetPwmBits, SwapOnVSync, etc. Do I have to implement those as well in my wrapper?

soyxan commented 7 years ago

Now I got it working. My FrameCanvas2 implemtation should be used only for calling SetPixel and GetPixel. For all other calls, FrameCanvas should be used.

Thanks for all your help!