Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tfilepath.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/txshsimplelevel.h"
Toshihiro Shimizu 890ddd
#include "toonz/preferences.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/onionskinmask.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*****************************************************************************************
Toshihiro Shimizu 890ddd
//    Macros
Toshihiro Shimizu 890ddd
//*****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define MINFADE 0.35
Toshihiro Shimizu 890ddd
#define MAXFADE 0.95
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*****************************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace
Toshihiro Shimizu 890ddd
//*****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
double inline getIncrement(int paperThickness)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct locals {
Toshihiro Shimizu 890ddd
		inline static void fillIncrements(double *values, int a, int b)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			double slope = (values[b] - values[a]) / (b - a);
Toshihiro Shimizu 890ddd
			for (int i = a + 1; i < b; ++i)
Toshihiro Shimizu 890ddd
				values[i] = values[i - 1] + slope;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}; // locals
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	static double Incr[101] = {-1.0};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (Incr[0] == -1.0) {
Toshihiro Shimizu 890ddd
		Incr[0] = 0.0;
Toshihiro Shimizu 890ddd
		Incr[10] = 0.05;
Toshihiro Shimizu 890ddd
		Incr[50] = 0.12;
Toshihiro Shimizu 890ddd
		Incr[90] = 0.3;
Toshihiro Shimizu 890ddd
		Incr[100] = MAXFADE - MINFADE;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		locals::fillIncrements(Incr, 0, 10);
Toshihiro Shimizu 890ddd
		locals::fillIncrements(Incr, 10, 50);
Toshihiro Shimizu 890ddd
		locals::fillIncrements(Incr, 50, 90);
Toshihiro Shimizu 890ddd
		locals::fillIncrements(Incr, 90, 100);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return Incr[paperThickness];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//***************************************************************************
Toshihiro Shimizu 890ddd
//    OnionSkinMask  implementation
Toshihiro Shimizu 890ddd
//***************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OnionSkinMask::clear()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_fos.clear();
Toshihiro Shimizu 890ddd
	m_mos.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_shiftTraceStatus = DISABLED;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_ghostAff[0] = TAffine();
Toshihiro Shimizu 890ddd
	m_ghostAff[1] = TAffine();
Toshihiro Shimizu 890ddd
	m_ghostCenter[0] = TPointD();
Toshihiro Shimizu 890ddd
	m_ghostCenter[1] = TPointD();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OnionSkinMask::getAll(int currentRow, vector<int> &output) const</int>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	output.clear();
Toshihiro Shimizu 890ddd
	output.reserve(m_fos.size() + m_mos.size());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<int>::const_iterator fosIt, fosEnd(m_fos.end());</int>
Toshihiro Shimizu 890ddd
	std::vector<int>::const_iterator mosIt, mosEnd(m_mos.end());</int>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (fosIt = m_fos.begin(), mosIt = m_mos.begin(); fosIt != fosEnd && mosIt != mosEnd;) {
Toshihiro Shimizu 890ddd
		int fos = *fosIt, mos = *mosIt + currentRow;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (fos < mos) {
Toshihiro Shimizu 890ddd
			if (fos != currentRow)
Toshihiro Shimizu 890ddd
				output.push_back(fos);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			++fosIt;
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			if (mos != currentRow)
Toshihiro Shimizu 890ddd
				output.push_back(mos);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			++mosIt;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (; fosIt != fosEnd; ++fosIt)
Toshihiro Shimizu 890ddd
		if (*fosIt != currentRow)
Toshihiro Shimizu 890ddd
			output.push_back(*fosIt);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (; mosIt != mosEnd; ++mosIt) {
Toshihiro Shimizu 890ddd
		int mos = *mosIt + currentRow;
Toshihiro Shimizu 890ddd
		if (mos != currentRow)
Toshihiro Shimizu 890ddd
			output.push_back(mos);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OnionSkinMask::setMos(int drow, bool on)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(drow != 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	typedef std::vector<int>::iterator Iter;</int>
Toshihiro Shimizu 890ddd
	std::pair<iter, iter=""> r = std::equal_range(m_mos.begin(), m_mos.end(), drow);</iter,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (on) {
Toshihiro Shimizu 890ddd
		if (r.first == r.second)
Toshihiro Shimizu 890ddd
			m_mos.insert(r.first, drow);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		if (r.first != r.second)
Toshihiro Shimizu 890ddd
			m_mos.erase(r.first, r.second);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OnionSkinMask::setFos(int row, bool on)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	typedef std::vector<int>::iterator Iter;</int>
Toshihiro Shimizu 890ddd
	std::pair<iter, iter=""> r = std::equal_range(m_fos.begin(), m_fos.end(), row);</iter,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (on) {
Toshihiro Shimizu 890ddd
		if (r.first == r.second)
Toshihiro Shimizu 890ddd
			m_fos.insert(r.first, row);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		if (r.first != r.second)
Toshihiro Shimizu 890ddd
			m_fos.erase(r.first, r.second);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool OnionSkinMask::isFos(int row) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return std::binary_search(m_fos.begin(), m_fos.end(), row);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool OnionSkinMask::isMos(int drow) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return std::binary_search(m_mos.begin(), m_mos.end(), drow);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool OnionSkinMask::getMosRange(int &drow0, int &drow1) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_mos.empty()) {
Toshihiro Shimizu 890ddd
		drow0 = 0, drow1 = -1;
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		drow0 = m_mos.front(), drow1 = m_mos.back();
Toshihiro Shimizu 890ddd
		return true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
double OnionSkinMask::getOnionSkinFade(int rowsDistance)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (rowsDistance == 0)
Toshihiro Shimizu 890ddd
		return 0.9;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double fade = MINFADE + abs(rowsDistance) * getIncrement(Preferences::instance()->getOnionPaperThickness());
Toshihiro Shimizu 890ddd
	return tcrop(fade, MINFADE, MAXFADE);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OnionSkinMask::setShiftTraceGhostAff(int index, const TAffine &aff)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(0 <= index && index < 2);
Toshihiro Shimizu 890ddd
	m_ghostAff[index] = aff;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OnionSkinMask::setShiftTraceGhostCenter(int index, const TPointD ¢er)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(0 <= index && index < 2);
Toshihiro Shimizu 890ddd
	m_ghostCenter[index] = center;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//***************************************************************************
Toshihiro Shimizu 890ddd
//    OnionSkinMaskModifier  implementation
Toshihiro Shimizu 890ddd
//***************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
OnionSkinMaskModifier::OnionSkinMaskModifier(OnionSkinMask mask, int currentRow)
Toshihiro Shimizu 890ddd
	: m_oldMask(mask), m_curMask(mask), m_firstRow(0), m_lastRow(0), m_curRow(currentRow), m_status(0)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OnionSkinMaskModifier::click(int row, bool isFos)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(m_status == 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_firstRow = m_lastRow = row;
Toshihiro Shimizu 890ddd
	if (isFos) {
Toshihiro Shimizu 890ddd
		assert(row != m_curRow);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (m_curMask.isEnabled() && m_curMask.isFos(row)) {
Toshihiro Shimizu 890ddd
			m_status = 2; // spegnere fos
Toshihiro Shimizu 890ddd
			m_curMask.setFos(row, false);
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			if (!m_curMask.isEnabled()) {
Toshihiro Shimizu 890ddd
				m_curMask.clear();
Toshihiro Shimizu 890ddd
				m_curMask.enable(true);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_curMask.setFos(row, true);
Toshihiro Shimizu 890ddd
			m_status = 3; // accendere fos
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		int drow = row - m_curRow;
Toshihiro Shimizu 890ddd
		if (drow != 0 && m_curMask.isEnabled() && m_curMask.isMos(drow)) {
Toshihiro Shimizu 890ddd
			m_status = 4; // spegnere mos
Toshihiro Shimizu 890ddd
			m_curMask.setMos(drow, false);
Toshihiro Shimizu 890ddd
		} else if (drow == 0) {
Toshihiro Shimizu 890ddd
			m_status = 8 + 4 + 1; // accendere mos; partito da 0
Toshihiro Shimizu 890ddd
		} else if (!m_curMask.isEnabled()) {
Toshihiro Shimizu 890ddd
			// e' disabilitato e ho fatto click in un punto vuoto: non faccio niente
Toshihiro Shimizu 890ddd
			m_status = 128; // errore
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			m_curMask.setMos(drow, true);
Toshihiro Shimizu 890ddd
			m_status = 4 + 1; // accendere mos;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OnionSkinMaskModifier::drag(int row)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_status & 128)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (row == m_lastRow)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_status |= 64; // moved
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int n = row - m_lastRow, d = 1;
Toshihiro Shimizu 890ddd
	if (n < 0)
Toshihiro Shimizu 890ddd
		n = -n, d = -d;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int oldr = m_lastRow, r = oldr + d;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 0; i < n; ++i, r += d) {
Toshihiro Shimizu 890ddd
		if (m_status & 4) {
Toshihiro Shimizu 890ddd
			if (!m_curMask.isEnabled()) {
Toshihiro Shimizu 890ddd
				m_curMask.clear();
Toshihiro Shimizu 890ddd
				m_curMask.enable(true);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			if (r != m_curRow)
Toshihiro Shimizu 890ddd
				m_curMask.setMos(r - m_curRow, (m_status & 1) != 0);
Toshihiro Shimizu 890ddd
		} else
Toshihiro Shimizu 890ddd
			m_curMask.setFos(r, (m_status & 1) != 0);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_lastRow = row;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OnionSkinMaskModifier::release(int row)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_status & 128)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	if ((m_status & 64) == 0   // non si e' mosso
Toshihiro Shimizu 890ddd
		&& (m_status & 8) == 8 // e' partito da zero
Toshihiro Shimizu 890ddd
		&& row == m_curRow) {
Toshihiro Shimizu 890ddd
		if (!m_curMask.isEmpty() && m_curMask.isEnabled())
Toshihiro Shimizu 890ddd
			m_curMask.enable(false);
Toshihiro Shimizu 890ddd
		else {
Toshihiro Shimizu 890ddd
			m_curMask.enable(true);
Toshihiro Shimizu 890ddd
			if (m_curMask.isEmpty()) {
Toshihiro Shimizu 890ddd
				m_curMask.setMos(-1, true);
Toshihiro Shimizu 890ddd
				m_curMask.setMos(-2, true);
Toshihiro Shimizu 890ddd
				m_curMask.setMos(-3, true);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}