Commit 4076f993 authored by Maciej Suminski's avatar Maciej Suminski
Browse files

Added a layer compositor for the Cairo backend.

parent 27113348
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ set(GAL_SRCS

    # Cairo GAL
    gal/cairo/cairo_gal.cpp
    gal/cairo/cairo_compositor.cpp
    )

add_library(gal STATIC ${GAL_SRCS})
+161 −0
Original line number Diff line number Diff line
/*i
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 2013 CERN
 * @author Maciej Suminski <maciej.suminski@cern.ch>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you may find one here:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * or you may search the http:O//www.gnu.org website for the version 2 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

/**
 * @file cairo_compositor.cpp
 * @brief Class that handles multitarget rendering (ie. to different textures/surfaces) and
 * later compositing into a single image (Cairo flavour).
 */

#include <gal/cairo/cairo_compositor.h>
#include <wx/log.h>

using namespace KiGfx;

CAIRO_COMPOSITOR::CAIRO_COMPOSITOR( cairo_t** aMainContext ) :
     m_current( 0 ), m_currentContext( aMainContext ), m_mainContext( *aMainContext )
{
    // Obtain the transformation matrix used in the main context
    cairo_get_matrix( m_mainContext, &m_matrix );
}


CAIRO_COMPOSITOR::~CAIRO_COMPOSITOR()
{
    clean();
}


void CAIRO_COMPOSITOR::Initialize()
{
    // Nothing has to be done
}


void CAIRO_COMPOSITOR::Resize( unsigned int aWidth, unsigned int aHeight )
{
    clean();

    m_width  = aWidth;
    m_height = aHeight;

    m_stride     = cairo_format_stride_for_width( CAIRO_FORMAT_ARGB32, m_width );
    m_bufferSize = m_stride * m_height;
}


unsigned int CAIRO_COMPOSITOR::GetBuffer()
{
    // Pixel storage
    BitmapPtr bitmap( new unsigned int[m_bufferSize] );

    // Create the Cairo surface
    cairo_surface_t* surface = cairo_image_surface_create_for_data(
                                                        (unsigned char*) bitmap.get(),
                                                        CAIRO_FORMAT_ARGB32, m_width,
                                                        m_height, m_stride );
    cairo_t* context = cairo_create( surface );
    #ifdef __WXDEBUG__
        cairo_status_t status = cairo_status( context );
        wxASSERT_MSG( status == CAIRO_STATUS_SUCCESS, "Cairo context creation error" );
    #endif /* __WXDEBUG__ */

    // Set default settings for the buffer
    cairo_set_antialias( context, CAIRO_ANTIALIAS_SUBPIXEL );
    cairo_set_line_join( context, CAIRO_LINE_JOIN_ROUND );
    cairo_set_line_cap( context, CAIRO_LINE_CAP_ROUND );

    // Use the same transformation matrix as the main context
    cairo_set_matrix( context, &m_matrix );

    // Store the new buffer
    CAIRO_BUFFER buffer = { context, surface, bitmap };
    m_buffers.push_back( buffer );

    return usedBuffers();
}


void CAIRO_COMPOSITOR::SetBuffer( unsigned int aBufferHandle )
{
    if( aBufferHandle <= usedBuffers() )
    {
        m_current = aBufferHandle - 1;
        *m_currentContext = m_buffers[m_current].context;
    }
#ifdef __WXDEBUG__
    else
        wxLogDebug( wxT( "Tried to use a not existing buffer" ) );
#endif
}


void CAIRO_COMPOSITOR::ClearBuffer()
{
    // Reset the transformation matrix, so it is possible to composite images using
    // screen coordinates instead of world coordinates
    cairo_identity_matrix( m_buffers[m_current].context );

    cairo_set_source_rgba( m_buffers[m_current].context, 0.0, 0.0, 0.0, 0.0 );
    cairo_rectangle( m_buffers[m_current].context, 0.0, 0.0, m_width, m_height );
    cairo_fill( m_buffers[m_current].context );

    // Restore the transformation matrix
    cairo_set_matrix( m_buffers[m_current].context, &m_matrix );
}


void CAIRO_COMPOSITOR::DrawBuffer( unsigned int aBufferHandle )
{
    if( aBufferHandle <= usedBuffers() )
    {
        // Reset the transformation matrix, so it is possible to composite images using
        // screen coordinates instead of world coordinates
        cairo_identity_matrix( m_mainContext );

        cairo_set_source_surface( m_mainContext, m_buffers[aBufferHandle - 1].surface, 0.0, 0.0 );
        cairo_paint( m_mainContext );

        // Restore the transformation matrix
        cairo_set_matrix( m_mainContext, &m_matrix );
    }
#ifdef __WXDEBUG__
    else
        wxLogDebug( wxT( "Tried to use a not existing buffer" ) );
#endif
}


void CAIRO_COMPOSITOR::clean()
{
    CAIRO_BUFFERS::const_iterator it;

    for( it = m_buffers.begin(); it != m_buffers.end(); ++it )
    {
        cairo_destroy( it->context );
        cairo_surface_destroy( it->surface );
    }

    m_buffers.clear();
}
+165 −138

File changed.

Preview size limit exceeded, changes collapsed.

+108 −0
Original line number Diff line number Diff line
/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 2013 CERN
 * @author Maciej Suminski <maciej.suminski@cern.ch>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you may find one here:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * or you may search the http://www.gnu.org website for the version 2 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

/**
 * @file cairo_compositor.h
 * @brief Class that handles multitarget rendering (ie. to different textures/surfaces) and
 * later compositing into a single image (Cairo flavour).
 */

#ifndef CAIRO_COMPOSITOR_H_
#define CAIRO_COMPOSITOR_H_

#include <gal/compositor.h>
#include <cairo.h>
#include <boost/smart_ptr/shared_array.hpp>
#include <deque>

namespace KiGfx
{

class CAIRO_COMPOSITOR : public COMPOSITOR
{
public:
    CAIRO_COMPOSITOR( cairo_t** aMainContext );
    virtual ~CAIRO_COMPOSITOR();

    /// @copydoc COMPOSITOR::Initialize()
    virtual void Initialize();

    /// @copydoc COMPOSITOR::Resize()
    virtual void Resize( unsigned int aWidth, unsigned int aHeight );

    /// @copydoc COMPOSITOR::GetBuffer()
    virtual unsigned int GetBuffer();

    /// @copydoc COMPOSITOR::SetBuffer()
    virtual void SetBuffer( unsigned int aBufferHandle );

    /// @copydoc COMPOSITOR::ClearBuffer()
    virtual void ClearBuffer();

    /// @copydoc COMPOSITOR::DrawBuffer()
    virtual void DrawBuffer( unsigned int aBufferHandle );

protected:
    typedef boost::shared_array<unsigned int> BitmapPtr;
    typedef struct
    {
        cairo_t* context;                   ///< Main texture handle
        cairo_surface_t* surface;           ///< Point to which an image from texture is attached
        BitmapPtr bitmap;                   ///< Pixel storage
    } CAIRO_BUFFER;

    unsigned int                m_current;                ///< Currently used buffer handle
    typedef std::deque<CAIRO_BUFFER> CAIRO_BUFFERS;

    /// Pointer to the current context, so it can be changed
    cairo_t**                   m_currentContext;

    /// Rendering target used for compositing (the main display)
    cairo_t*                    m_mainContext;

    /// Transformation matrix
    cairo_matrix_t              m_matrix;

    /// Stores information about initialized buffers
    CAIRO_BUFFERS               m_buffers;

    unsigned int m_stride;              ///< Stride to use given the desired format and width
    unsigned int m_bufferSize;          ///< Amount of memory needed to store a buffer

    /**
     * Function clean()
     * performs freeing of resources.
     */
    void clean();

    /// Returns number of currently used buffers
    unsigned int usedBuffers()
    {
        return m_buffers.size();
    }
};

} // namespace KiGfx

#endif /* COMPOSITOR_H_ */
+25 −14
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@
#include <cairo.h>

#include <gal/graphics_abstraction_layer.h>

#include <boost/smart_ptr/shared_ptr.hpp>

#if defined(__WXMSW__)
#define SCREEN_DEPTH 24
@@ -62,6 +62,8 @@
 */
namespace KiGfx
{
class CAIRO_COMPOSITOR;

class CAIRO_GAL : public GAL, public wxWindow
{
public:
@@ -299,11 +301,15 @@ private:
    /// Super class definition
    typedef GAL super;

    // Compositing variables
    boost::shared_ptr<CAIRO_COMPOSITOR> compositor; ///< Object for layers compositing
    unsigned int mainBuffer;                        ///< Handle to the main buffer
    unsigned int overlayBuffer;                     ///< Handle to the overlay buffer

    // Variables related to wxWidgets
    wxWindow*                   parentWindow;       ///< Parent window
    wxEvtHandler*               mouseListener;      ///< Mouse listener
    wxEvtHandler*               paintListener;      ///< Paint listener
    wxRect                      clientRectangle;    ///< Area definition of the surface
    unsigned int                bufferSize;         ///< Size of buffers cairoOutput, bitmapBuffers
    unsigned char*              wxOutput;           ///< wxImage comaptible buffer

@@ -315,11 +321,6 @@ private:
    wxBitmap*                   cursorPixelsSaved;      ///< Saved cursor pixels
    int                         cursorSize;             ///< Cursor size

    // Variables for the grouping function
    int                         actualGroupIndex;   ///< The index of the actual group
    bool                        isGrouping;         ///< Is grouping enabled ?
    bool                        isElementAdded;     ///< Was an graphic element added ?

    /// Maximum number of arguments for one command
    static const int MAX_CAIRO_ARGUMENTS = 6;

@@ -352,6 +353,9 @@ private:
        cairo_path_t* cairoPath;                    ///< Pointer to a Cairo path
    } GroupElement;

    // Variables for the grouping function
    bool                        isGrouping;         ///< Is grouping enabled ?
    bool                        isElementAdded;     ///< Was an graphic element added ?
    typedef std::deque<GroupElement> Group;         ///< A graphic group type definition
    std::map<int, Group>        groups;             ///< List of graphic groups
    unsigned int                groupCounter;       ///< Counter used for generating keys for groups
@@ -359,8 +363,9 @@ private:

    // Variables related to Cairo <-> wxWidgets
    cairo_matrix_t      cairoWorldScreenMatrix; ///< Cairo world to screen transformation matrix
    cairo_t*            cairoImage;             ///< Cairo image
    cairo_surface_t*    cairoSurface;           ///< Cairo surface
    cairo_t*            currentContext;         ///< Currently used Cairo context for drawing
    cairo_t*            context;                ///< Cairo image
    cairo_surface_t*    surface;                ///< Cairo surface
    unsigned int*       bitmapBuffer;           ///< Storage of the cairo image
    unsigned int*       bitmapBufferBackup;     ///< Backup storage of the cairo image
    int                 stride;                 ///< Stride value for Cairo
@@ -400,15 +405,21 @@ private:
    /// Prepare Cairo surfaces for drawing
    void initSurface();

    // Destroy Cairo surfaces when are not needed anymore
    /// Destroy Cairo surfaces when are not needed anymore
    void deinitSurface();

    /// Prepare the compositor
    void setCompositor();

    /**
     * @brief Returns a valid key that can be used as a new group number.
     *
     * @return An unique group number that is not used by any other group.
     */
    unsigned int getNewGroupNumber();

    /// Format used to store pixels
    static const cairo_format_t GAL_FORMAT = CAIRO_FORMAT_RGB24;
};
} // namespace KiGfx