1
2
3 // TnzCore includes
4 #include "tfilepath.h"
5
6 // TnzLib includes
7 #include "toonz/txshsimplelevel.h"
8 #include "toonz/preferences.h"
9
10 #include "toonz/onionskinmask.h"
11
12 //*****************************************************************************************
13 // Macros
14 //*****************************************************************************************
15
16 #define MINFADE 0.35
17 #define MAXFADE 0.95
18
19 //*****************************************************************************************
20 // Local namespace
21 //*****************************************************************************************
22
23 namespace {
24
getIncrement(int paperThickness)25 double inline getIncrement(int paperThickness) {
26 struct locals {
27 inline static void fillIncrements(double *values, int a, int b) {
28 double slope = (values[b] - values[a]) / (b - a);
29 for (int i = a + 1; i < b; ++i) values[i] = values[i - 1] + slope;
30 }
31 }; // locals
32
33 static double Incr[101] = {-1.0};
34
35 if (Incr[0] == -1.0) {
36 Incr[0] = 0.0;
37 Incr[10] = 0.05;
38 Incr[50] = 0.12;
39 Incr[90] = 0.3;
40 Incr[100] = MAXFADE - MINFADE;
41
42 locals::fillIncrements(Incr, 0, 10);
43 locals::fillIncrements(Incr, 10, 50);
44 locals::fillIncrements(Incr, 50, 90);
45 locals::fillIncrements(Incr, 90, 100);
46 }
47
48 return Incr[paperThickness];
49 }
50
51 } // namespace
52
53 //***************************************************************************
54 // OnionSkinMask implementation
55 //***************************************************************************
56
clear()57 void OnionSkinMask::clear() {
58 m_fos.clear();
59 m_mos.clear();
60
61 m_shiftTraceStatus = DISABLED;
62
63 m_ghostAff[0] = TAffine();
64 m_ghostAff[1] = TAffine();
65 m_ghostCenter[0] = TPointD();
66 m_ghostCenter[1] = TPointD();
67 m_ghostFrame[0] = 0;
68 m_ghostFrame[1] = 0;
69 }
70
71 //-------------------------------------------------------------------
72
getAll(int currentRow,std::vector<int> & output) const73 void OnionSkinMask::getAll(int currentRow, std::vector<int> &output) const {
74 output.clear();
75 output.reserve(m_fos.size() + m_mos.size());
76
77 std::vector<int>::const_iterator fosIt, fosEnd(m_fos.end());
78 std::vector<int>::const_iterator mosIt, mosEnd(m_mos.end());
79
80 for (fosIt = m_fos.begin(), mosIt = m_mos.begin();
81 fosIt != fosEnd && mosIt != mosEnd;) {
82 int fos = *fosIt, mos = *mosIt + currentRow;
83
84 if (fos < mos) {
85 if (fos != currentRow) output.push_back(fos);
86
87 ++fosIt;
88 } else {
89 if (mos != currentRow) output.push_back(mos);
90
91 ++mosIt;
92 }
93 }
94
95 for (; fosIt != fosEnd; ++fosIt)
96 if (*fosIt != currentRow) output.push_back(*fosIt);
97
98 for (; mosIt != mosEnd; ++mosIt) {
99 int mos = *mosIt + currentRow;
100 if (mos != currentRow) output.push_back(mos);
101 }
102 }
103
104 //-------------------------------------------------------------------
105
setMos(int drow,bool on)106 void OnionSkinMask::setMos(int drow, bool on) {
107 assert(drow != 0);
108
109 typedef std::vector<int>::iterator Iter;
110 std::pair<Iter, Iter> r = std::equal_range(m_mos.begin(), m_mos.end(), drow);
111
112 if (on) {
113 if (r.first == r.second) m_mos.insert(r.first, drow);
114 } else {
115 if (r.first != r.second) m_mos.erase(r.first, r.second);
116 }
117 }
118
119 //-------------------------------------------------------------------
120
setFos(int row,bool on)121 void OnionSkinMask::setFos(int row, bool on) {
122 typedef std::vector<int>::iterator Iter;
123 std::pair<Iter, Iter> r = std::equal_range(m_fos.begin(), m_fos.end(), row);
124
125 if (on) {
126 if (r.first == r.second) m_fos.insert(r.first, row);
127 } else {
128 if (r.first != r.second) m_fos.erase(r.first, r.second);
129 }
130 }
131
132 //-------------------------------------------------------------------
133
isFos(int row) const134 bool OnionSkinMask::isFos(int row) const {
135 return std::binary_search(m_fos.begin(), m_fos.end(), row);
136 }
137
138 //-------------------------------------------------------------------
139
isMos(int drow) const140 bool OnionSkinMask::isMos(int drow) const {
141 return std::binary_search(m_mos.begin(), m_mos.end(), drow);
142 }
143
144 //-------------------------------------------------------------------
145
getMosRange(int & drow0,int & drow1) const146 bool OnionSkinMask::getMosRange(int &drow0, int &drow1) const {
147 if (m_mos.empty()) {
148 drow0 = 0, drow1 = -1;
149 return false;
150 } else {
151 drow0 = m_mos.front(), drow1 = m_mos.back();
152 return true;
153 }
154 }
155
156 //-------------------------------------------------------------------
157
getOnionSkinFade(int rowsDistance)158 double OnionSkinMask::getOnionSkinFade(int rowsDistance) {
159 if (rowsDistance == 0) return 0.9;
160
161 double fade =
162 MINFADE +
163 abs(rowsDistance) *
164 getIncrement(Preferences::instance()->getOnionPaperThickness());
165 return tcrop(fade, MINFADE, MAXFADE);
166 }
167
168 //-------------------------------------------------------------------
169
setShiftTraceGhostAff(int index,const TAffine & aff)170 void OnionSkinMask::setShiftTraceGhostAff(int index, const TAffine &aff) {
171 assert(0 <= index && index < 2);
172 m_ghostAff[index] = aff;
173 }
174
175 //-------------------------------------------------------------------
176
setShiftTraceGhostCenter(int index,const TPointD & center)177 void OnionSkinMask::setShiftTraceGhostCenter(int index, const TPointD ¢er) {
178 assert(0 <= index && index < 2);
179 m_ghostCenter[index] = center;
180 }
181
182 //***************************************************************************
183 // OnionSkinMaskModifier implementation
184 //***************************************************************************
185
OnionSkinMaskModifier(OnionSkinMask mask,int currentRow)186 OnionSkinMaskModifier::OnionSkinMaskModifier(OnionSkinMask mask, int currentRow)
187 : m_oldMask(mask)
188 , m_curMask(mask)
189 , m_firstRow(0)
190 , m_lastRow(0)
191 , m_curRow(currentRow)
192 , m_status(0) {}
193
194 //-------------------------------------------------------------------
195
click(int row,bool isFos)196 void OnionSkinMaskModifier::click(int row, bool isFos) {
197 assert(m_status == 0);
198
199 m_firstRow = m_lastRow = row;
200 if (isFos) {
201 assert(row != m_curRow);
202
203 if (m_curMask.isEnabled() && m_curMask.isFos(row)) {
204 m_status = 2; // spegnere fos
205 m_curMask.setFos(row, false);
206 } else {
207 if (!m_curMask.isEnabled()) {
208 m_curMask.clear();
209 m_curMask.enable(true);
210 }
211
212 m_curMask.setFos(row, true);
213 m_status = 3; // accendere fos
214 }
215 } else {
216 int drow = row - m_curRow;
217 if (drow != 0 && m_curMask.isEnabled() && m_curMask.isMos(drow)) {
218 m_status = 4; // spegnere mos
219 m_curMask.setMos(drow, false);
220 } else if (drow == 0) {
221 m_status = 8 + 4 + 1; // accendere mos; partito da 0
222 } else {
223 if (!m_curMask.isEnabled()) m_curMask.enable(true);
224 m_curMask.setMos(drow, true);
225 m_status = 4 + 1; // accendere mos;
226 }
227 }
228 }
229
230 //-------------------------------------------------------------------
231
drag(int row)232 void OnionSkinMaskModifier::drag(int row) {
233 if (m_status & 128) return;
234
235 if (row == m_lastRow) return;
236
237 m_status |= 64; // moved
238
239 int n = row - m_lastRow, d = 1;
240 if (n < 0) n = -n, d = -d;
241
242 int oldr = m_lastRow, r = oldr + d;
243
244 for (int i = 0; i < n; ++i, r += d) {
245 if (m_status & 4) {
246 if (!m_curMask.isEnabled()) {
247 m_curMask.clear();
248 m_curMask.enable(true);
249 }
250 if (r != m_curRow) m_curMask.setMos(r - m_curRow, (m_status & 1) != 0);
251 } else
252 m_curMask.setFos(r, (m_status & 1) != 0);
253 }
254
255 m_lastRow = row;
256 }
257
258 //-------------------------------------------------------------------
259
release(int row)260 void OnionSkinMaskModifier::release(int row) {
261 if (m_status & 128) return;
262 if ((m_status & 64) == 0 // non si e' mosso
263 && (m_status & 8) == 8 // e' partito da zero
264 && row == m_curRow) {
265 if (!m_curMask.isEmpty() && m_curMask.isEnabled())
266 m_curMask.enable(false);
267 else {
268 m_curMask.enable(true);
269 if (m_curMask.isEmpty()) {
270 m_curMask.setMos(-1, true);
271 m_curMask.setMos(-2, true);
272 m_curMask.setMos(-3, true);
273 }
274 }
275 }
276 }
277