Posted by: nanaproject | April 17, 2012

An introduction to the image processing interfaces from release of 0.2.2

In the release of 0.2.2, Nana C++ Library provides a mechanism which can flexibly configure the image processing algorithms. For an abstract algorithm, there would be many implementations. For example, Nana C++ Library provides two stretch algorithms, they are bilinear interoplation and proximal interoplation, you can switch the algorithms under your requirement.
See the example at:
http://stdex.sourceforge.net/help/paint/image_process_selector.htm

The algorithms provided by Nana are implemented without specific platform instructions for cross-platform, they should work fine in different compiler environment. In some situations, an extreme efficiency is desired. Although the Nana C++ Library does not provide such an algorithm with specific instructions, it is possible to implement the algorithm by yourself for your requirment, and configure it to make Nana apply it.

Let’s implement a blend algorithm with MMX instruction.

To implement a blend algorithm that can be applied by Nana C++ Library, we have to implement the algorithm with class blend_interface, the class is defined by Nana in header file <nana/paint/image_process_interface.hpp>.

class blend_interface
{
public:
    virtual ~blend_interface() = 0;
    virtual void process(nana::paint::drawable_type dw_dst, const nana::rectangle& r_dst, const paint::pixel_buffer& s_pixbuf, const nana::point& s_pos, double fade_rate) const = 0;
};

dw_dst: the destination object.
r_dst:    the destination blend area.
s_pixbuf: the source pixel buffer.
s_pos:    the source blend coordinate.
fade_rate: the rate at blend.

The blend area is always valid, it is calculated by Nana before passing it to the function. So we can use it without check.

The semantics of this interface is:
dw_dst = dw_dst * fade_rate + s_pixbuf * (1 – fade_rate)

Let’s start!

#include <nana/paint/image_process_interface.hpp>

class blend_mmx
    : public nana::paint::image_process::blend_interface
{

    virtual void process(nana::paint::drawable_type dw_dst, const nana::rectangle& r_dst, const nana::paint::pixel_buffer& s_pixbuf, const nana::point& s_pos, double fade_rate) const
    {
        nana::paint::pixel_buffer d_pixbuf(dw_dst, r_dst.y, r_dst.height);
        nana::pixel_rgb_t * d_rgb = d_pixbuf.raw_ptr();

        if(d_rgb)
        {
            d_rgb += r_dst.x;
            nana::pixel_rgb_t * s_rgb = s_pixbuf.raw_ptr(s_pos.y) + s_pos.x;

            const unsigned rest = r_dst.width & 0x3;
            const unsigned length_align4 = r_dst.width – rest;

            unsigned d_step_width = d_pixbuf.size().width;
            unsigned s_step_width = s_pixbuf.size().width;

            unsigned i_d_rate = static_cast<unsigned>(fade_rate * 255);
            unsigned i_s_rate = 255 – i_d_rate;

            __asm
            {
                pxor xmm7, xmm7
                movd xmm0, i_d_rate
                punpcklwd xmm0, xmm0
                punpcklwd xmm0, xmm0
                punpcklwd xmm0, xmm0

                movd xmm1, i_s_rate
                punpcklwd xmm1, xmm1
                punpcklwd xmm1, xmm1
                punpcklwd xmm1, xmm1
            }

            for(unsigned line = 0; line < r_dst.height; ++line)
            {
                __asm
                {
                    push eax
                    push ebx
                    push edx
                    mov edx, dword ptr[length_align4]
                    mov    eax, dword ptr[d_rgb]
                    mov ebx, dword ptr[s_rgb]
                    lea    edx, [edx * 4 + eax]
blend_mmx_3_for_each_pixel_in_line_loop_start:
                    cmp eax, edx
                    je blend_mmx_3_for_each_pixel_in_line_loop_end

                    //eax[0], eax[1]
                    movq xmm2, qword ptr[eax]
                    movq xmm3, qword ptr[ebx]
                    punpcklbw xmm2, xmm7
                    punpcklbw xmm3, xmm7
                    pmullw xmm2, xmm0
                    pmullw xmm3, xmm1
                    paddw    xmm2, xmm3
                    psrlw    xmm2, 8
                    packuswb xmm2, xmm7
                    movq    qword ptr[eax], xmm2
                        
                    //eax[2], eax[3]
                    movq xmm2, qword ptr[eax + 8]
                    movq xmm3, qword ptr[ebx + 8]
                    punpcklbw xmm2, xmm7
                    punpcklbw xmm3, xmm7
                    pmullw xmm2, xmm0
                    pmullw xmm3, xmm1
                    paddw    xmm2, xmm3
                    psrlw    xmm2, 8
                    packuswb xmm2, xmm7
                    movq    qword ptr[eax + 8], xmm2
                        
                    add eax, 16
                    add ebx, 16

                    jmp blend_mmx_3_for_each_pixel_in_line_loop_start
blend_mmx_3_for_each_pixel_in_line_loop_end:
                    push ecx
                    mov ecx, dword ptr[rest]
                    cmp ecx, 0
                    je blend_mmx_3_for_each_rest_pixel_loop_end
blend_mmx_3_for_each_rest_pixel_loop_start:
                    movd xmm2, dword ptr[eax]
                    movd xmm3, dword ptr[ebx]
                    punpcklbw xmm2, xmm7
                    punpcklbw xmm3, xmm7
                    pmullw xmm2, xmm0
                    pmullw xmm3, xmm1
                    paddw    xmm2, xmm3
                    psrlw    xmm2, 8
                    packuswb xmm2, xmm7
                    movd    dword ptr[eax], xmm2
                    add eax, 4
                    add ebx, 4
                    loop blend_mmx_3_for_each_rest_pixel_loop_start
blend_mmx_3_for_each_rest_pixel_loop_end:
                    pop ecx
                    pop edx
                    pop ebx
                    pop eax
                }
                d_rgb += d_step_width;
                s_rgb += s_step_width;
            }

            __asm emms

            nana::rectangle r = r_dst;
            r.y = 0;
            d_pixbuf.paste(r, dw_dst, r_dst.x, r_dst.y);
        }
    }
};

Apply it!

#include <nana/gui/wvl.hpp>
#include <nana/gui/timer.hpp>
#include <nana/paint/image_process_selector.hpp>

//Include the definition of blend_mmx that we implemented before.

class blend_form
    : public nana::gui::form
{
public:
    blend_form()
        :form(nana::gui::API::make_center(450, 300))
        ,fade_rate_(0.1), delta_(0.1)
    {
        this->show();

        nana::paint::image img(STR(“image01.bmp”));
        s_graph_.make(img.size().width, img.size().height);
        img.paste(s_graph_, 0, 0);

        d_image_.open(STR(“image02.bmp”));
        d_graph_.make(d_image_.size().width, d_image_.size().height);

        timer_.make_tick(nana::make_fun(*this, &tsform::_m_blend));
        timer_.interval(10);

        //Install the blend_mmx and apply it.
        nana::paint::image_process::selector sl;
        sl.add_blend<blend_mmx>(“blend_mmx”); //Give it a name
        sl.blend(“blend_mmx”); //Apply it
    }
private:
    void _m_blend()
    {
        fade_rate_ += delta_;
        if(fade_rate_ > 1)
        {
            fade_rate_ = 1;
            delta_ = -0.01;
        }
        else if(fade_rate_ < 0)
        {
            fade_rate_ = 0;
            delta_ = 0.01;
        }
                
        d_image_.paste(d_graph_, 0, 0);

        //The blend operation, it employes the blend_mmx algorithm.
        s_graph_.blend(d_graph_, 0, 0, fade_rate_);

        nana::gui::drawing drawing(*this);
        drawing.clear();
        drawing.bitblt(0, 0, 450, 300, d_graph_, 0, 0);
        drawing.update();
    }
private:
    double    fade_rate_;
    double    delta_;
    timer    timer_;
    nana::paint::graphics s_graph_, d_graph_;
    nana::paint::image d_image_;
};

It shows a method that user can implement an algorithm instead of the algorithm that Nana provides for various requirement.

Enjoy!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: