void DMDFrame::marqueeScrollY(int scrollBy) {
    scrollBy = scrollBy % height;

    if(scrollBy < 0) { // Scroll up
        DMDFrame frame = subFrame(0, 0, width, -scrollBy); // save topmost
        movePixels(0, -scrollBy, 0, 0, width, height+scrollBy); // move
        copyFrame(frame, 0, height+scrollBy); // drop back at bottom edge
    } else { // Scroll down
        DMDFrame frame = subFrame(0, height-scrollBy, width, scrollBy); // save bottommost
        movePixels(0, 0, 0, scrollBy, width, height-scrollBy); // move
        copyFrame(frame, 0, 0); // drop back at top edge
    }
}
void DMDFrame::scrollY(int scrollBy) {
    if(abs(scrollBy) >= height) { // scrolling over the whole display
        // scrolling will erase everything
        drawFilledBox(0, 0, width-1, height-1, GRAPHICS_OFF);
    }
    else if(scrollBy < 0) { // Scroll up
        movePixels(0, -scrollBy, 0, 0, width, height + scrollBy);
        drawFilledBox(0, height+scrollBy, width, height, GRAPHICS_OFF);
    }
    else if(scrollBy > 0) { // Scroll down
        movePixels(0, 0, 0, scrollBy, width, height - scrollBy);
        drawFilledBox(0, 0, width, scrollBy, GRAPHICS_OFF);
    }
}
void DMDFrame::scrollX(int scrollBy) {
    if(abs(scrollBy) >= width) { // scrolling over the whole display!
        // scrolling will erase everything
        drawFilledBox(0, 0, width-1, height-1, GRAPHICS_OFF);
    }
    else if(scrollBy < 0) { // Scroll left
        movePixels(-scrollBy, 0, 0, 0, width + scrollBy, height);
        drawFilledBox(width+scrollBy, 0, width, height, GRAPHICS_OFF);
    }
    else { // Scroll right
        movePixels(0, 0, scrollBy, 0, width - scrollBy, height);
        drawFilledBox(0, 0, scrollBy, height, GRAPHICS_OFF);
    }
}
void DMDFrame::marqueeScrollX(int scrollBy) {
    // Scrolling is basically the same as normal scrolling, but we save/restore the overlapping
    // area in between to create the marquee effect
    scrollBy = scrollBy % width;

    if(scrollBy < 0)  { // Scroll left
        DMDFrame frame = subFrame(0, 0, -scrollBy, height); // save leftmost
        movePixels(-scrollBy, 0, 0, 0, width + scrollBy, height); // move
        copyFrame(frame, width+scrollBy, 0); // drop back at right edge
    } else { // Scroll right
        DMDFrame frame = subFrame(width-scrollBy, 0, scrollBy, height); // save rightmost
        movePixels(0, 0, scrollBy, 0, width - scrollBy, height); // move
        copyFrame(frame, 0, 0); // drop back at left edge
    }
}
void ac::ParticleEmiter::draw_flash(cv::Mat &frame) {
    speed = 10;
    static int flash_index = 0;
    static cv::Vec3b black(0,0,0);
    cv::Vec3b color(rand()%255, rand()%255, rand()%255);
    movePixels();//move values before drawing
    for(int z = 0; z < h; ++z) {
        for(int i = 0; i < w; ++i) {
            int x_pos = part[i][z].x;
            int y_pos = part[i][z].y;
            if(x_pos > 0 && x_pos < frame.cols && y_pos > 0 && y_pos < frame.rows) {
                cv::Vec3b &pixel = frame.at<cv::Vec3b>(y_pos, x_pos);
                switch(flash_index) {
                    case 0:
                        pixel = part[i][z].pixel;
                        break;
                    case 1:
                        pixel = black;
                        break;
                    case 2:
                        pixel = color;
                        break;
                }
                ++flash_index;
                if(flash_index > 2)
                    flash_index = 0;
            }
        }
    }
}
// draw pixel values to frame
void ac::ParticleEmiter::draw(cv::Mat &frame) {
    speed = 1;
    movePixels();//move values before drawing
    for(int z = 0; z < h; ++z) {
        for(int i = 0; i < w; ++i) {
            int x_pos = part[i][z].x;
            int y_pos = part[i][z].y;
            if(x_pos > 0 && x_pos < frame.cols && y_pos > 0 && y_pos < frame.rows) {
                cv::Vec3b &pixel = frame.at<cv::Vec3b>(y_pos, x_pos);
                pixel = part[i][z].pixel;
            }
        }
    }
}
void ac::ParticleEmiter::draw_op(cv::Mat &frame) {
    speed = 1;
    movePixels();
    for(int z = 0; z < h; ++z) {
        for(int i = 0; i < w; ++i) {
            int x_pos = part[i][z].x;
            int y_pos = part[i][z].y;
            if(x_pos > 0 && x_pos < frame.cols && y_pos > 0 && y_pos < frame.rows) {
                cv::Vec3b &pixel = frame.at<cv::Vec3b>(y_pos, x_pos);
                for(int j = 0; j < 3; ++j)
                	pixel[j] = part[i][z].pixel[j]^pixel[j];
            }
        }
    }
}
// draw movement fast
void ac::ParticleEmiter::draw_move(cv::Mat &frame) {
    speed = 50;
    movePixels();//move values before drawing
    static double alpha = 1.0, alpha_max = 6.0;
    for(int z = 0; z < h; ++z) {
        for(int i = 0; i < w; ++i) {
            int x_pos = part[i][z].x;
            int y_pos = part[i][z].y;
            if(x_pos > 0 && x_pos < frame.cols && y_pos > 0 && y_pos < frame.rows) {
                cv::Vec3b &pixel = frame.at<cv::Vec3b>(y_pos, x_pos);
                pixel = part[i][z].pixel;
            }
        }
    }
    static int dir = 1;
    procPos(dir, alpha, alpha_max);
}
void ac::ParticleEmiter::draw_alpha(cv::Mat &frame) {
    speed = 20;
    movePixels();//move values before drawing
    static double alpha = 1.0, alpha_max = 10;
    for(int z = 0; z < h; ++z) {
        for(int i = 0; i < w; ++i) {
            int x_pos = part[i][z].x;
            int y_pos = part[i][z].y;
            if(x_pos > 0 && x_pos < frame.cols && y_pos > 0 && y_pos < frame.rows) {
                cv::Vec3b &pixel = frame.at<cv::Vec3b>(y_pos, x_pos);
                for(int j = 0; j < 3; ++j)
                    pixel[j] += part[i][z].pixel[j]*static_cast<unsigned char>(alpha);
                
            }
        }
    }
    static int dir = 1;
    procPos(dir, alpha, alpha_max, 15, 0.01);
}