Blame synfig-core/src/synfig/rendering/software/task/taskpixelgammasw.cpp

bf609b
/* === S Y N F I G ========================================================= */
bf609b
/*!	\file synfig/rendering/software/task/taskpixelgammasw.cpp
bf609b
**	\brief TaskPixelGammaSW
bf609b
**
bf609b
**	$Id$
bf609b
**
bf609b
**	\legal
1911b2
**	......... ... 2016-2018 Ivan Mahonin
bf609b
**
bf609b
**	This package is free software; you can redistribute it and/or
bf609b
**	modify it under the terms of the GNU General Public License as
bf609b
**	published by the Free Software Foundation; either version 2 of
bf609b
**	the License, or (at your option) any later version.
bf609b
**
bf609b
**	This package is distributed in the hope that it will be useful,
bf609b
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
bf609b
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
bf609b
**	General Public License for more details.
bf609b
**	\endlegal
bf609b
*/
bf609b
/* ========================================================================= */
bf609b
bf609b
/* === H E A D E R S ======================================================= */
bf609b
bf609b
#ifdef USING_PCH
bf609b
#	include "pch.h"
bf609b
#else
bf609b
#ifdef HAVE_CONFIG_H
bf609b
#	include <config.h></config.h>
bf609b
#endif
bf609b
bf609b
#include <synfig debug="" debugsurface.h=""></synfig>
bf609b
#include <synfig general.h=""></synfig>
bf609b
39c97b
#include "../../common/task/taskpixelprocessor.h"
39c97b
#include "tasksw.h"
bf609b
bf609b
#endif
bf609b
bf609b
using namespace synfig;
bf609b
using namespace rendering;
bf609b
bf609b
/* === M A C R O S ========================================================= */
bf609b
bf609b
/* === G L O B A L S ======================================================= */
bf609b
bf609b
/* === P R O C E D U R E S ================================================= */
bf609b
bf609b
/* === M E T H O D S ======================================================= */
bf609b
39c97b
namespace {
c74fcf
39c97b
class TaskPixelGammaSW: public TaskPixelGamma, public TaskSW
39c97b
{
39c97b
public:
39c97b
	typedef etl::handle<taskpixelgammasw> Handle;</taskpixelgammasw>
39c97b
	static Token token;
5e2754
	virtual Token::Handle get_token() const { return token.handle(); }
da4398
39c97b
private:
39c97b
	typedef void Func(ColorReal &dst, const ColorReal &src, const ColorReal &gamma);
da4398
39c97b
	struct Params
bf609b
	{
39c97b
		ColorReal *dst;
39c97b
		int dst_stride;
39c97b
		const ColorReal *src;
39c97b
		int src_stride;
39c97b
		int width;
39c97b
		int height;
39c97b
39c97b
		union {
a4bbdd
			ColorReal gamma[3];
39c97b
			struct {
a4bbdd
				ColorReal gamma_r, gamma_g, gamma_b;
28bbc1
			};
28bbc1
		};
bf609b
39c97b
		Params():
39c97b
			dst(), dst_stride(),
39c97b
			src(), src_stride(),
39c97b
			width(), height(),
a4bbdd
			gamma_r(1.0), gamma_g(1.0), gamma_b(1.0)
39c97b
		{ }
39c97b
39c97b
		Params(
39c97b
			Color *dst,
39c97b
			int dst_stride,
39c97b
			const Color *src,
39c97b
			int src_stride,
39c97b
			int width,
39c97b
			int height,
39c97b
			ColorReal gamma_r,
39c97b
			ColorReal gamma_g,
a4bbdd
			ColorReal gamma_b
39c97b
		):
39c97b
			dst((ColorReal*)dst), dst_stride(dst_stride),
39c97b
			src((const ColorReal*)src), src_stride(src_stride),
39c97b
			width(width), height(height),
a4bbdd
			gamma_r(gamma_r), gamma_g(gamma_g), gamma_b(gamma_b)
39c97b
		{ }
39c97b
	};
28bbc1
898f7c
	static inline ColorReal clamp(const ColorReal &x)
898f7c
	{
898f7c
		const ColorReal max = ColorReal(1.0)/real_low_precision<colorreal>();</colorreal>
898f7c
		return std::max(-max, std::min(max, x));
898f7c
	}
898f7c
a4bbdd
	static inline ColorReal clamp_positive(const ColorReal &x)
898f7c
	{
a4bbdd
		const ColorReal max = ColorReal(1.0)/real_low_precision<colorreal>();</colorreal>
a4bbdd
		return std::max(real_low_precision<colorreal>(), std::min(max, x));</colorreal>
817417
	}
817417
39c97b
	static inline void func_none(ColorReal&, const ColorReal&, const ColorReal&) { }
39c97b
	static inline void func_copy(ColorReal &dst, const ColorReal &src, const ColorReal&)
39c97b
		{ dst = src; }
39c97b
	static inline void func_one(ColorReal &dst, const ColorReal &, const ColorReal &)
39c97b
		{ dst = ColorReal(1.0); }
a4bbdd
	static inline void func_pow(ColorReal &dst, const ColorReal &src, const ColorReal &gamma)
a4bbdd
		{ dst = clamp(src < 0 ? -pow(-src, gamma) : pow(src, gamma)); }
a4bbdd
a4bbdd
	template<func fb="" fg,="" fr,="" func=""></func>
a4bbdd
	static void process_rgb(const Params &p) {
a4bbdd
		if (p.src == p.dst)
39c97b
		{
39c97b
			assert(p.src_stride == p.dst_stride);
39c97b
39c97b
			int dst_dr = 4*(p.dst_stride - p.width);
39c97b
			int row_size = 4*p.width;
39c97b
			ColorReal *dst = p.dst;
39c97b
			for(ColorReal *dst_end = dst + 4*p.dst_stride*p.height; dst != dst_end; dst += dst_dr)
39c97b
			{
39c97b
				for(ColorReal *dst_row_end = dst + row_size; dst != dst_row_end; dst += 4)
bf609b
				{
39c97b
					fr(dst[0], dst[0], p.gamma_r);
39c97b
					fg(dst[1], dst[1], p.gamma_g);
39c97b
					fb(dst[2], dst[2], p.gamma_b);
bf609b
				}
bf609b
			}
39c97b
		}
39c97b
		else
39c97b
		{
39c97b
			assert(p.src + 4*p.src_stride*p.height <= p.dst || p.dst + 4*p.dst_stride*p.height <= p.src);
39c97b
39c97b
			int dst_dr = 4*(p.dst_stride - p.width);
39c97b
			int src_dr = 4*(p.src_stride - p.width);
39c97b
			int row_size = 4*p.width;
39c97b
			ColorReal *dst = p.dst;
39c97b
			const ColorReal *src = p.src;
39c97b
			for(ColorReal *dst_end = dst + 4*p.dst_stride*p.height; dst != dst_end; dst += dst_dr, src += src_dr)
bf609b
			{
39c97b
				for(ColorReal *dst_row_end = dst + row_size; dst != dst_row_end; dst += 4, src += 4)
bf609b
				{
39c97b
					fr(dst[0], src[0], p.gamma_r);
39c97b
					fg(dst[1], src[1], p.gamma_g);
39c97b
					fb(dst[2], src[2], p.gamma_b);
a4bbdd
					dst[3] = src[3];
bf609b
				}
bf609b
			}
bf609b
		}
39c97b
	}
bf609b
39c97b
	template<func fg="" fr,="" func=""></func>
39c97b
	static void process_rg(const Params &p) {
a4bbdd
		if ( approximate_equal_lp(p.gamma_b, ColorReal(0.0))) process_rgb<fr, fg,="" func_one="">(p); else</fr,>
a4bbdd
		if (!approximate_equal_lp(p.gamma_b, ColorReal(1.0))) process_rgb<fr, fg,="" func_pow="">(p); else</fr,>
a4bbdd
		if (p.src == p.dst)                                   process_rgb<fr, fg,="" func_none="">(p); else</fr,>
898f7c
				                                              process_rgb<fr, fg,="" func_copy="">(p);</fr,>
39c97b
	}
bf609b
39c97b
	template<func fr=""></func>
39c97b
	static void process_r(const Params &p) {
a4bbdd
		if ( approximate_equal_lp(p.gamma_g, ColorReal(0.0))) process_rg<fr, func_one="">(p); else</fr,>
a4bbdd
		if (!approximate_equal_lp(p.gamma_g, ColorReal(1.0))) process_rg<fr, func_pow="">(p); else</fr,>
a4bbdd
		if (p.src == p.dst)                                   process_rg<fr, func_none="">(p); else</fr,>
898f7c
				                                              process_rg<fr, func_copy="">(p);</fr,>
39c97b
	}
bf609b
39c97b
	static void process(const Params &p) {
a4bbdd
		if ( approximate_equal_lp(p.gamma_r, ColorReal(0.0))) process_r<func_one>(p); else</func_one>
a4bbdd
		if (!approximate_equal_lp(p.gamma_r, ColorReal(1.0))) process_r<func_pow>(p); else</func_pow>
a4bbdd
		if (p.src == p.dst)                                   process_r<func_none>(p); else</func_none>
898f7c
				                                              process_r<func_copy>(p);</func_copy>
39c97b
	}
bf609b
39c97b
public:
5e2754
	virtual bool run(RunParams&) const {
39c97b
		if (!is_valid() || !sub_task() || !sub_task()->is_valid())
39c97b
			return true;
39c97b
39c97b
		RectInt rd = target_rect;
39c97b
		VectorInt offset = get_offset();
39c97b
		RectInt rs = sub_task()->target_rect + rd.get_min() + offset;
39c97b
		etl::set_intersect(rs, rs, rd);
39c97b
		if (rs.is_valid())
39c97b
		{
5e2754
			LockWrite ldst(this);
5e2754
			if (!ldst) return false;
5e2754
			LockRead lsrc(sub_task());
5e2754
			if (!lsrc) return false;
5e2754
39c97b
			synfig::Surface &dst = ldst->get_surface();
39c97b
			const synfig::Surface &src = lsrc->get_surface();
39c97b
39c97b
			process(Params(
39c97b
				&dst[rs.miny][rs.minx],
39c97b
				dst.get_pitch()/sizeof(Color),
39c97b
				&src[rs.miny - rd.miny - offset[1]][rs.minx - rd.minx - offset[0]],
39c97b
				src.get_pitch()/sizeof(Color),
39c97b
				rs.get_width(),
39c97b
				rs.get_height(),
a4bbdd
				clamp_positive(gamma.get_r()),
a4bbdd
				clamp_positive(gamma.get_g()),
a4bbdd
				clamp_positive(gamma.get_b()) ));
39c97b
		}
bf609b
da4398
		return true;
39c97b
	}
39c97b
};
da4398
bf609b
5e2754
Task::Token TaskPixelGammaSW::token(
5e2754
	DescReal<taskpixelgammasw, taskpixelgamma="">("PixelGammaSW") );</taskpixelgammasw,>
bf609b
39c97b
} // end of anonimous namespace
bf609b
bf609b
/* === E N T R Y P O I N T ================================================= */