Blame synfig-core/src/synfig/rendering/surface.h

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