|
|
3c2463 |
/* === S Y N F I G ========================================================= */
|
|
|
3c2463 |
/*! \file synfig/rendering/surface.h
|
|
|
3c2463 |
** \brief Surface Header
|
|
|
3c2463 |
**
|
|
|
3c2463 |
** $Id$
|
|
|
3c2463 |
**
|
|
|
3c2463 |
** \legal
|
|
|
9310e7 |
** ......... ... 2015-2018 Ivan Mahonin
|
|
|
3c2463 |
**
|
|
|
3c2463 |
** This package is free software; you can redistribute it and/or
|
|
|
3c2463 |
** modify it under the terms of the GNU General Public License as
|
|
|
3c2463 |
** published by the Free Software Foundation; either version 2 of
|
|
|
3c2463 |
** the License, or (at your option) any later version.
|
|
|
3c2463 |
**
|
|
|
3c2463 |
** This package is distributed in the hope that it will be useful,
|
|
|
3c2463 |
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
3c2463 |
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
3c2463 |
** General Public License for more details.
|
|
|
3c2463 |
** \endlegal
|
|
|
3c2463 |
*/
|
|
|
3c2463 |
/* ========================================================================= */
|
|
|
3c2463 |
|
|
|
3c2463 |
/* === S T A R T =========================================================== */
|
|
|
3c2463 |
|
|
|
3c2463 |
#ifndef __SYNFIG_RENDERING_SURFACE_H
|
|
|
3c2463 |
#define __SYNFIG_RENDERING_SURFACE_H
|
|
|
3c2463 |
|
|
|
3c2463 |
/* === H E A D E R S ======================================================= */
|
|
|
3c2463 |
|
|
|
32ec48 |
#include <map></map>
|
|
|
32ec48 |
#include <vector></vector>
|
|
|
32ec48 |
|
|
Rodolfo Ribeiro Gomes |
424d47 |
#include <mutex></mutex>
|
|
|
9310e7 |
#include <glibmm threads.h=""></glibmm>
|
|
|
9310e7 |
|
|
|
9310e7 |
#include <etl handle=""></etl>
|
|
|
9310e7 |
|
|
|
8823f5 |
#include <synfig color.h=""></synfig>
|
|
|
232715 |
#include <synfig vector.h=""></synfig>
|
|
|
9310e7 |
#include <synfig token.h=""></synfig>
|
|
|
ba51c9 |
#include <synfig rect.h=""></synfig>
|
|
|
ff7fb9 |
|
|
|
3c2463 |
/* === M A C R O S ========================================================= */
|
|
|
3c2463 |
|
|
|
3c2463 |
/* === T Y P E D E F S ===================================================== */
|
|
|
3c2463 |
|
|
|
3c2463 |
/* === C L A S S E S & S T R U C T S ======================================= */
|
|
|
3c2463 |
|
|
|
3c2463 |
namespace synfig
|
|
|
3c2463 |
{
|
|
|
3c2463 |
namespace rendering
|
|
|
3c2463 |
{
|
|
|
3c2463 |
|
|
|
9310e7 |
|
|
|
9310e7 |
class Surface: public etl::shared_object
|
|
|
3c2463 |
{
|
|
|
3c2463 |
public:
|
|
|
3c2463 |
typedef etl::handle<surface> Handle;</surface>
|
|
|
9310e7 |
typedef Surface* (*Fabric)();
|
|
|
9310e7 |
|
|
|
5e2754 |
class DescBase {
|
|
|
5e2754 |
protected:
|
|
|
5e2754 |
template<typename t=""></typename>
|
|
|
5e2754 |
static Surface* fabric_template()
|
|
|
5e2754 |
{ return new T(); }
|
|
|
9310e7 |
public:
|
|
|
9310e7 |
const String name;
|
|
|
5e2754 |
const Fabric fabric;
|
|
|
5e2754 |
|
|
|
5e2754 |
DescBase(const String &name, Fabric fabric):
|
|
|
5e2754 |
name(name),
|
|
|
5e2754 |
fabric(fabric)
|
|
|
5e2754 |
{ assert(fabric); }
|
|
|
5e2754 |
};
|
|
|
5e2754 |
|
|
|
5e2754 |
class Token: public synfig::Token, public DescBase {
|
|
|
5e2754 |
public:
|
|
|
5e2754 |
typedef ConstRef<token> Handle;</token>
|
|
|
9310e7 |
|
|
|
9310e7 |
private:
|
|
|
9310e7 |
template<typename t=""></typename>
|
|
|
9310e7 |
T* fabric_template()
|
|
|
9310e7 |
{ return new T(); }
|
|
|
9310e7 |
|
|
|
9310e7 |
public:
|
|
|
5e2754 |
Token(const DescBase &desc):
|
|
|
5e2754 |
synfig::Token(token.handle()),
|
|
|
5e2754 |
DescBase(desc) { }
|
|
|
9310e7 |
|
|
|
9310e7 |
inline Handle handle() const
|
|
|
9310e7 |
{ return Handle(*this); }
|
|
|
9310e7 |
};
|
|
|
9310e7 |
|
|
|
5e2754 |
template<typename type=""></typename>
|
|
|
5e2754 |
class Desc: public DescBase {
|
|
|
5e2754 |
public:
|
|
|
5e2754 |
Desc(const String &name):
|
|
|
5e2754 |
DescBase(
|
|
|
5e2754 |
name,
|
|
|
5e2754 |
&DescBase::fabric_template<type> )</type>
|
|
|
5e2754 |
{ }
|
|
|
5e2754 |
};
|
|
|
5e2754 |
|
|
|
5e2754 |
|
|
|
9310e7 |
static synfig::Token token;
|
|
|
9310e7 |
virtual Token::Handle get_token() const = 0;
|
|
|
3c2463 |
|
|
|
8823f5 |
private:
|
|
|
9310e7 |
bool blank;
|
|
|
8823f5 |
int width;
|
|
|
8823f5 |
int height;
|
|
|
8823f5 |
|
|
|
3c2463 |
protected:
|
|
|
9310e7 |
void set_desc(int width, int height, bool blank);
|
|
|
9310e7 |
|
|
|
5e2754 |
virtual bool create_vfunc(int /* width */, int /* height */)
|
|
|
9310e7 |
{ return false; }
|
|
|
5e2754 |
virtual bool assign_vfunc(const Surface & /* other */)
|
|
|
9310e7 |
{ return false; }
|
|
|
9310e7 |
virtual bool clear_vfunc()
|
|
|
9310e7 |
{ return false; }
|
|
|
9310e7 |
virtual bool reset_vfunc()
|
|
|
9310e7 |
{ return false; }
|
|
|
9310e7 |
//! Implementations of this function should to work quick
|
|
|
9310e7 |
virtual const Color* get_pixels_pointer_vfunc() const
|
|
|
9310e7 |
{ return NULL; }
|
|
|
9310e7 |
virtual bool get_pixels_vfunc(Color *dest) const;
|
|
|
3c2463 |
|
|
|
3c2463 |
public:
|
|
|
8823f5 |
Surface();
|
|
|
8823f5 |
virtual ~Surface();
|
|
|
8823f5 |
|
|
|
9310e7 |
virtual bool is_read_only() const
|
|
|
9310e7 |
{ return false; }
|
|
|
9310e7 |
|
|
|
9310e7 |
bool create(int width, int height);
|
|
|
9310e7 |
bool assign(const Surface &other);
|
|
|
9310e7 |
bool clear();
|
|
|
9310e7 |
bool reset();
|
|
|
9310e7 |
|
|
|
9310e7 |
bool assign(const Color *pixels, int width, int height);
|
|
|
9310e7 |
bool assign(const Color *pixels)
|
|
|
9310e7 |
{ return assign(pixels, get_width(), get_height()); }
|
|
|
9310e7 |
|
|
|
9310e7 |
bool touch();
|
|
|
9310e7 |
|
|
|
9310e7 |
const Color* get_pixels_pointer() const;
|
|
|
9310e7 |
bool get_pixels(Color *dest) const;
|
|
|
9310e7 |
|
|
|
9310e7 |
int get_width() const
|
|
|
9310e7 |
{ return width; }
|
|
|
9310e7 |
int get_height() const
|
|
|
9310e7 |
{ return height; }
|
|
|
9310e7 |
int get_pixels_count() const
|
|
|
9310e7 |
{ return get_width()*get_height(); }
|
|
|
9310e7 |
size_t get_buffer_size() const
|
|
|
9310e7 |
{ return get_pixels_count()*sizeof(Color); }
|
|
|
9310e7 |
bool is_exists() const
|
|
|
9310e7 |
{ return get_width() > 0 && get_height() > 0; }
|
|
|
9310e7 |
bool is_blank() const
|
|
|
9310e7 |
{ return blank || !is_exists(); }
|
|
|
9310e7 |
};
|
|
|
ff7fb9 |
|
|
|
9310e7 |
|
|
|
9310e7 |
class SurfaceResource: public etl::shared_object
|
|
|
9310e7 |
{
|
|
|
9310e7 |
public:
|
|
|
9310e7 |
typedef etl::handle<surfaceresource> Handle;</surfaceresource>
|
|
|
9310e7 |
typedef std::map<surface::token::handle, surface::handle=""> Map;</surface::token::handle,>
|
|
|
9310e7 |
|
|
|
99cd7f |
template<typename bool="" exclusive="" typesurface,="" write,=""></typename>
|
|
|
ba51c9 |
class LockBase {
|
|
|
99cd7f |
public:
|
|
|
ba51c9 |
const Handle resource;
|
|
|
99cd7f |
const bool full;
|
|
|
5e2754 |
const RectInt rect;
|
|
|
99cd7f |
|
|
|
9310e7 |
private:
|
|
|
99cd7f |
bool lock_token;
|
|
|
99cd7f |
Surface::Token::Handle token;
|
|
|
99cd7f |
Surface::Handle surface;
|
|
|
99cd7f |
|
|
|
99cd7f |
void lock() {
|
|
|
5e2754 |
if (resource) {
|
|
|
99cd7f |
if (write) resource->rwlock.writer_lock();
|
|
|
99cd7f |
else resource->rwlock.reader_lock();
|
|
|
5e2754 |
}
|
|
|
99cd7f |
}
|
|
|
99cd7f |
void unlock() {
|
|
|
5e2754 |
if (resource) {
|
|
|
64ccfe |
surface.reset();
|
|
|
99cd7f |
if (write) resource->rwlock.writer_unlock();
|
|
|
99cd7f |
else resource->rwlock.reader_unlock();
|
|
|
5e2754 |
}
|
|
|
99cd7f |
}
|
|
|
99cd7f |
|
|
|
5e2754 |
LockBase(const LockBase&): full(), lock_token() { }
|
|
|
5e2754 |
|
|
|
9310e7 |
public:
|
|
|
99cd7f |
explicit LockBase(const Handle &resource):
|
|
|
99cd7f |
resource(resource), full(true), lock_token(false)
|
|
|
99cd7f |
{ lock(); }
|
|
|
99cd7f |
LockBase(const Handle &resource, const RectInt &rect):
|
|
|
99cd7f |
resource(resource), full(false), rect(rect), lock_token(false)
|
|
|
99cd7f |
{ lock(); }
|
|
|
99cd7f |
LockBase(const Handle &resource, const Surface::Token::Handle &token):
|
|
|
99cd7f |
resource(resource), full(true), lock_token(true), token(token)
|
|
|
99cd7f |
{ lock(); }
|
|
|
99cd7f |
LockBase(const Handle &resource, const RectInt &rect, const Surface::Token::Handle &token):
|
|
|
48c23f |
resource(resource), full(false), rect(rect), lock_token(true), token(token)
|
|
|
99cd7f |
{ lock(); }
|
|
|
99cd7f |
~LockBase() { unlock(); }
|
|
|
99cd7f |
|
|
|
99cd7f |
bool convert(const Surface::Token::Handle &token, bool create = true, bool any = false) {
|
|
|
99cd7f |
if (!resource) return false;
|
|
|
99cd7f |
if (lock_token && token != this->token) return false;
|
|
|
99cd7f |
return surface = resource->get_surface(token, exclusive, full, rect, create, any);
|
|
|
99cd7f |
}
|
|
|
99cd7f |
|
|
|
99cd7f |
template<typename t=""></typename>
|
|
|
99cd7f |
bool convert(bool create = true, bool any = false)
|
|
|
5e2754 |
{ return convert(T::token.handle(), create, any); }
|
|
|
99cd7f |
|
|
|
99cd7f |
bool is_lock_tocken() const
|
|
|
99cd7f |
{ return lock_token; }
|
|
|
99cd7f |
Surface::Token::Handle get_lock_token() const
|
|
|
99cd7f |
{ return token; }
|
|
|
99cd7f |
Surface::Token::Handle get_token() const
|
|
|
99cd7f |
{ return surface ? surface->get_token() : Surface::Token::Handle(); }
|
|
|
ba51c9 |
const Handle& get_resource() const
|
|
|
ba51c9 |
{ return resource; }
|
|
|
5e2754 |
const Surface::Handle& get_handle() const
|
|
|
99cd7f |
{ return surface; }
|
|
|
99cd7f |
template<typename t=""></typename>
|
|
|
99cd7f |
etl::handle<t> cast() const</t>
|
|
|
99cd7f |
{ return etl::handle<t>::cast_dynamic(surface); }</t>
|
|
|
ba51c9 |
TypeSurface* get_surface() const
|
|
|
9310e7 |
{ return surface.get(); }
|
|
|
99cd7f |
operator bool() const
|
|
|
9310e7 |
{ return surface; }
|
|
|
9310e7 |
};
|
|
|
9310e7 |
|
|
|
99cd7f |
typedef LockBase<const false="" false,="" surface,=""> LockReadBase;</const>
|
|
|
99cd7f |
typedef LockBase<surface, true="" true,=""> LockWriteBase;</surface,>
|
|
|
99cd7f |
typedef LockBase<surface, false,="" true=""> SemiLockWriteBase; //!< helps to avoid crashes but may cause visual artifacts</surface,>
|
|
|
9310e7 |
|
|
|
9310e7 |
template<typename t=""></typename>
|
|
|
9310e7 |
class LockRead: public LockReadBase {
|
|
|
9310e7 |
public:
|
|
|
9310e7 |
typedef T Type;
|
|
|
ba51c9 |
explicit LockRead(const Handle &resource):
|
|
|
99cd7f |
LockReadBase(resource, Type::token.handle())
|
|
|
99cd7f |
{ convert(get_lock_token()); }
|
|
|
ba51c9 |
LockRead(const Handle &resource, const RectInt &rect):
|
|
|
99cd7f |
LockReadBase(resource, rect, Type::token.handle())
|
|
|
99cd7f |
{ convert(get_lock_token()); }
|
|
|
45e00a |
LockRead(const Handle &resource, const Surface::Token::Handle &token):
|
|
|
99cd7f |
LockReadBase(resource, token)
|
|
|
99cd7f |
{ convert(get_lock_token()); }
|
|
|
99cd7f |
LockRead(const Handle &resource, const RectInt &rect, const Surface::Token::Handle &token):
|
|
|
99cd7f |
LockReadBase(resource, rect, token)
|
|
|
99cd7f |
{ convert(get_lock_token()); }
|
|
|
5e2754 |
etl::handle<type> cast_handle() const</type>
|
|
|
99cd7f |
{ return cast<type>(); }</type>
|
|
|
5e2754 |
const Type* get() const
|
|
|
5e2754 |
{ return dynamic_cast<type*>(get_handle().get()); }</type*>
|
|
|
538b8c |
const Type* operator->() const
|
|
|
5e2754 |
{ assert(get()); return get(); }
|
|
|
9310e7 |
const Type& operator*() const
|
|
|
5e2754 |
{ assert(get()); return *get(); }
|
|
|
9310e7 |
};
|
|
|
9310e7 |
|
|
|
9310e7 |
template<typename t=""></typename>
|
|
|
9310e7 |
class LockWrite: public LockWriteBase {
|
|
|
9310e7 |
public:
|
|
|
9310e7 |
typedef T Type;
|
|
|
ba51c9 |
explicit LockWrite(const Handle &resource):
|
|
|
99cd7f |
LockWriteBase(resource, Type::token.handle())
|
|
|
99cd7f |
{ convert(get_lock_token()); }
|
|
|
ba51c9 |
LockWrite(const Handle &resource, const RectInt &rect):
|
|
|
99cd7f |
LockWriteBase(resource, rect, Type::token.handle())
|
|
|
99cd7f |
{ convert(get_lock_token()); }
|
|
|
45e00a |
LockWrite(const Handle &resource, const Surface::Token::Handle &token):
|
|
|
99cd7f |
LockWriteBase(resource, token)
|
|
|
99cd7f |
{ convert(get_lock_token()); }
|
|
|
99cd7f |
LockWrite(const Handle &resource, const RectInt &rect, const Surface::Token::Handle &token):
|
|
|
99cd7f |
LockWriteBase(resource, rect, token)
|
|
|
99cd7f |
{ convert(get_lock_token()); }
|
|
|
5e2754 |
etl::handle<type> cast_handle() const</type>
|
|
|
99cd7f |
{ return cast<type>(); }</type>
|
|
|
5e2754 |
Type* get() const
|
|
|
5e2754 |
{ return dynamic_cast<type*>(get_handle().get()); }</type*>
|
|
|
ba51c9 |
Type* operator->() const
|
|
|
5e2754 |
{ assert(get()); return get(); }
|
|
|
ba51c9 |
Type& operator*() const
|
|
|
5e2754 |
{ assert(get()); return *get(); }
|
|
|
ba51c9 |
};
|
|
|
ba51c9 |
|
|
|
ba51c9 |
template<typename t=""></typename>
|
|
|
ba51c9 |
class SemiLockWrite: public SemiLockWriteBase {
|
|
|
ba51c9 |
public:
|
|
|
ba51c9 |
typedef T Type;
|
|
|
ba51c9 |
explicit SemiLockWrite(const Handle &resource):
|
|
|
99cd7f |
SemiLockWriteBase(resource, Type::token.handle())
|
|
|
99cd7f |
{ convert(get_lock_token()); }
|
|
|
ba51c9 |
SemiLockWrite(const Handle &resource, const RectInt &rect):
|
|
|
99cd7f |
SemiLockWriteBase(resource, rect, Type::token.handle())
|
|
|
99cd7f |
{ convert(get_lock_token()); }
|
|
|
45e00a |
SemiLockWrite(const Handle &resource, const Surface::Token::Handle &token):
|
|
|
99cd7f |
SemiLockWriteBase(resource, token)
|
|
|
99cd7f |
{ convert(get_lock_token()); }
|
|
|
99cd7f |
SemiLockWrite(const Handle &resource, const RectInt &rect, const Surface::Token::Handle &token):
|
|
|
99cd7f |
SemiLockWriteBase(resource, rect, token)
|
|
|
99cd7f |
{ convert(get_lock_token()); }
|
|
|
5e2754 |
etl::handle<type> cast_handle() const</type>
|
|
|
99cd7f |
{ return cast<type>(); }</type>
|
|
|
5e2754 |
Type* get() const
|
|
|
5e2754 |
{ return dynamic_cast<type*>(get_handle().get()); }</type*>
|
|
|
538b8c |
Type* operator->() const
|
|
|
5e2754 |
{ assert(get()); return get(); }
|
|
|
9310e7 |
Type& operator*() const
|
|
|
5e2754 |
{ assert(get()); return *get(); }
|
|
|
9310e7 |
};
|
|
|
9310e7 |
|
|
|
9310e7 |
private:
|
|
|
99cd7f |
static int last_id;
|
|
|
99cd7f |
|
|
|
99cd7f |
int id;
|
|
|
9310e7 |
int width;
|
|
|
9310e7 |
int height;
|
|
|
ba51c9 |
bool blank;
|
|
|
9310e7 |
Map surfaces;
|
|
|
9310e7 |
|
|
Rodolfo Ribeiro Gomes |
424d47 |
mutable std::mutex mutex;
|
|
|
5e2754 |
mutable Glib::Threads::RWLock rwlock;
|
|
|
9310e7 |
|
|
|
99cd7f |
Surface::Handle get_surface(
|
|
|
99cd7f |
const Surface::Token::Handle &token,
|
|
|
99cd7f |
bool exclusive,
|
|
|
99cd7f |
bool full,
|
|
|
99cd7f |
const RectInt &rect,
|
|
|
99cd7f |
bool create,
|
|
|
99cd7f |
bool any );
|
|
|
9310e7 |
|
|
|
9310e7 |
public:
|
|
|
9310e7 |
SurfaceResource();
|
|
|
9310e7 |
SurfaceResource(Surface::Handle surface);
|
|
|
9310e7 |
virtual ~SurfaceResource();
|
|
|
9310e7 |
|
|
|
538b8c |
void create(int width, int height);
|
|
|
9310e7 |
void assign(Surface::Handle surface);
|
|
|
9310e7 |
void clear();
|
|
|
9310e7 |
void reset();
|
|
|
9310e7 |
|
|
|
da4398 |
void create(const VectorInt &x)
|
|
|
da4398 |
{ create(x[0], x[1]); }
|
|
|
da4398 |
|
|
|
99cd7f |
int get_id() const //!< helps to debug of renderer optimizers
|
|
|
99cd7f |
{ return id; }
|
|
|
9310e7 |
int get_width() const
|
|
Rodolfo Ribeiro Gomes |
424d47 |
{ std::lock_guard<std::mutex> lock(mutex); return width; }</std::mutex>
|
|
|
9310e7 |
int get_height() const
|
|
Rodolfo Ribeiro Gomes |
424d47 |
{ std::lock_guard<std::mutex> lock(mutex); return height; }</std::mutex>
|
|
|
da4398 |
VectorInt get_size() const
|
|
Rodolfo Ribeiro Gomes |
424d47 |
{ std::lock_guard<std::mutex> lock(mutex); return VectorInt(width, height); }</std::mutex>
|
|
|
9310e7 |
bool is_exists() const
|
|
Rodolfo Ribeiro Gomes |
424d47 |
{ std::lock_guard<std::mutex> lock(mutex); return width > 0 && height > 0; }</std::mutex>
|
|
|
ba51c9 |
bool is_blank() const
|
|
Rodolfo Ribeiro Gomes |
424d47 |
{ std::lock_guard<std::mutex> lock(mutex); return blank; }</std::mutex>
|
|
|
ba51c9 |
bool has_surface(const Surface::Token::Handle &token) const
|
|
Rodolfo Ribeiro Gomes |
424d47 |
{ std::lock_guard<std::mutex> lock(mutex); return surfaces.count(token); }</std::mutex>
|
|
|
da4398 |
template<typename t=""></typename>
|
|
|
da4398 |
bool has_surface() const
|
|
|
da4398 |
{ return has_surface(T::token.handle()); }
|
|
|
99cd7f |
bool get_tokens(std::vector<surface::token::handle> &outTokens) const {</surface::token::handle>
|
|
Rodolfo Ribeiro Gomes |
424d47 |
std::lock_guard<std::mutex> lock(mutex);</std::mutex>
|
|
|
99cd7f |
for(Map::const_iterator i = surfaces.begin(); i != surfaces.end(); ++i)
|
|
|
99cd7f |
outTokens.push_back(i->first);
|
|
|
99cd7f |
return !surfaces.empty();
|
|
|
99cd7f |
}
|
|
|
3c2463 |
};
|
|
|
3c2463 |
|
|
|
9310e7 |
|
|
|
3c2463 |
} /* end namespace rendering */
|
|
|
3c2463 |
} /* end namespace synfig */
|
|
|
3c2463 |
|
|
|
3c2463 |
/* -- E N D ----------------------------------------------------------------- */
|
|
|
3c2463 |
|
|
|
3c2463 |
#endif
|