1
2
3 #include "tools/stylepicker.h"
4 #include "tcolorstyles.h"
5 #include "tstroke.h"
6 #include "tofflinegl.h"
7 #include "tvectorrenderdata.h"
8 #include "tvectorimage.h"
9 #include "ttoonzimage.h"
10 #include "trasterimage.h"
11 #include "toonz/dpiscale.h"
12 #include "tpixelutils.h"
13 #include "tregion.h"
14 #include "toonzqt/gutil.h"
15
16 #include <QRect>
17
18 //---------------------------------------------------------
19
StylePicker(const TImageP & image)20 StylePicker::StylePicker(const TImageP &image)
21 : m_image(image), m_palette(image->getPalette()) {}
22
23 //---------------------------------------------------------
24
StylePicker(const TImageP & image,const TPaletteP & palette)25 StylePicker::StylePicker(const TImageP &image, const TPaletteP &palette)
26 : m_image(image), m_palette(palette) {}
27
28 //---------------------------------------------------------
29
getRasterPoint(const TPointD & p) const30 TPoint StylePicker::getRasterPoint(const TPointD &p) const {
31 if (TToonzImageP ti = m_image) {
32 // DpiScale dpiScale(ti);
33 TDimension size = ti->getSize();
34 return TPoint(tround(0.5 * size.lx + p.x), /// dpiScale.getSx()),
35 tround(0.5 * size.ly + p.y)); /// dpiScale.getSy()));
36 } else if (TRasterImageP ri = m_image) {
37 // DpiScale dpiScale(ri);
38 TDimension size = ri->getRaster()->getSize();
39 return TPoint(tround(0.5 * size.lx + p.x), // /dpiScale.getSx()),
40 tround(0.5 * size.ly + p.y)); // /dpiScale.getSy()));
41 } else
42 return TPoint(tround(p.x), tround(p.y));
43 }
44
45 //---------------------------------------------------------
46 /*-- (StylePickerTool内で)LineとAreaを切り替えてPickできる。mode: 0=Area,
47 * 1=Line, 2=Line&Areas(default) --*/
pickStyleId(const TPointD & pos,double radius,double scale2,int mode) const48 int StylePicker::pickStyleId(const TPointD &pos, double radius, double scale2,
49 int mode) const {
50 int styleId = 0;
51 if (TToonzImageP ti = m_image) {
52 TRasterCM32P ras = ti->getRaster();
53 TPoint point = getRasterPoint(pos);
54 if (!ras->getBounds().contains(point)) return -1;
55 TPixelCM32 col = ras->pixels(point.y)[point.x];
56
57 switch (mode) {
58 case 0: // AREAS
59 styleId = col.getPaint();
60 break;
61 case 1: // LINES
62 styleId = col.getInk();
63 break;
64 case 2: // ALL (Line & Area)
65 default:
66 styleId = col.isPurePaint() ? col.getPaint() : col.getInk();
67 break;
68 }
69 } else if (TRasterImageP ri = m_image) {
70 const TPalette *palette = m_palette.getPointer();
71 if (!palette) return -1;
72 TRaster32P ras = ri->getRaster();
73 if (!ras) return -1;
74 TPoint point = getRasterPoint(pos);
75 if (!ras->getBounds().contains(point)) return -1;
76 TPixel32 col = ras->pixels(point.y)[point.x];
77 styleId = palette->getClosestStyle(col);
78 } else if (TVectorImageP vi = m_image) {
79 // prima cerca lo stile della regione piu' vicina
80 TRegion *r = vi->getRegion(pos);
81 if (r) styleId = r->getStyle();
82 bool strokeFound;
83 double dist2, w, thick;
84 UINT index;
85 //! funzionerebbe ancora meglio con un getNearestStroke che considera
86 // la thickness, cioe' la min distance dalla outline e non dalla centerLine
87 strokeFound = vi->getNearestStroke(pos, w, index, dist2);
88 if (strokeFound) {
89 int devPixRatio = getDevPixRatio();
90 dist2 *= scale2;
91 TStroke *stroke = vi->getStroke(index);
92 thick = stroke->getThickPoint(w).thick;
93 double len2 = thick * thick * scale2;
94 const double minDist2 =
95 (styleId == 0) ? radius * radius * (double)(devPixRatio * devPixRatio)
96 : 0;
97 double checkDist = std::max(minDist2, len2);
98 if (dist2 < checkDist) {
99 assert(stroke);
100 styleId = stroke->getStyle();
101 }
102 }
103 }
104 return styleId;
105 }
106
107 //---------------------------------------------------------
108 /*--- Toonz Raster LevelのToneを拾う。 ---*/
pickTone(const TPointD & pos) const109 int StylePicker::pickTone(const TPointD &pos) const {
110 if (TToonzImageP ti = m_image) {
111 TRasterCM32P ras = ti->getRaster();
112 if (!ras) return -1;
113 TPoint point = getRasterPoint(pos);
114 if (!ras->getBounds().contains(point)) return -1;
115 TPixelCM32 col = ras->pixels(point.y)[point.x];
116
117 return col.getTone();
118 } else
119 return -1;
120 }
121
122 //---------------------------------------------------------
123
pickColor(const TPointD & pos,double radius,double scale2) const124 TPixel32 StylePicker::pickColor(const TPointD &pos, double radius,
125 double scale2) const {
126 TToonzImageP ti = m_image;
127 TRasterImageP ri = m_image;
128 TVectorImageP vi = m_image;
129 if (!!ri) // !!ti || !!ri)
130 {
131 TRasterP raster;
132 // if(ti)
133 // raster = ti->getRGBM(true);
134 // else
135 raster = ri->getRaster();
136
137 TPoint point = getRasterPoint(pos);
138 if (!raster->getBounds().contains(point)) return TPixel32::Transparent;
139
140 TRaster32P raster32 = raster;
141 if (raster32) return raster32->pixels(point.y)[point.x];
142
143 TRasterGR8P rasterGR8 = raster;
144 if (rasterGR8) return toPixel32(rasterGR8->pixels(point.y)[point.x]);
145 } else if (vi) {
146 const TPalette *palette = m_palette.getPointer();
147 if (!palette) return TPixel32::Transparent;
148 int styleId = pickStyleId(pos, radius, scale2);
149 if (0 <= styleId && styleId < palette->getStyleCount())
150 return palette->getStyle(styleId)->getAverageColor();
151 } else if (ti) {
152 const TPalette *palette = m_palette.getPointer();
153 if (!palette) return TPixel32::Transparent;
154 int paintId = pickStyleId(pos, radius, scale2, 0);
155 int inkId = pickStyleId(pos, radius, scale2, 1);
156 int tone = pickTone(pos);
157 TPixel32 ink, paint;
158 if (0 <= inkId && inkId < palette->getStyleCount())
159 ink = palette->getStyle(inkId)->getAverageColor();
160 if (0 <= paintId && paintId < palette->getStyleCount())
161 paint = palette->getStyle(paintId)->getAverageColor();
162
163 if (tone == 0)
164 return ink;
165 else if (tone == 255)
166 return paint;
167 else
168 return blend(ink, paint, tone, TPixelCM32::getMaxTone());
169 }
170 return TPixel32::Transparent;
171 }
172
173 //---------------------------------------------------------
174
pickAverageColor(const TRectD & rect) const175 TPixel32 StylePicker::pickAverageColor(const TRectD &rect) const {
176 TRasterImageP ri = m_image;
177 assert(ri);
178 if (!!ri) {
179 TRasterP raster;
180 raster = ri->getRaster();
181
182 TPoint topLeft = getRasterPoint(rect.getP00());
183 TPoint bottomRight = getRasterPoint(rect.getP11());
184
185 if (!raster->getBounds().overlaps(TRect(topLeft, bottomRight)))
186 return TPixel32::Transparent;
187
188 topLeft.x = std::max(0, topLeft.x);
189 topLeft.y = std::max(0, topLeft.y);
190 bottomRight.x = std::min(raster->getLx(), bottomRight.x);
191 bottomRight.y = std::min(raster->getLy(), bottomRight.y);
192
193 TRaster32P raster32 = raster;
194 assert(raster32);
195 if (raster32) {
196 UINT r = 0, g = 0, b = 0, m = 0, size = 0;
197 for (int y = topLeft.y; y < bottomRight.y; y++) {
198 TPixel32 *p = &raster32->pixels(y)[topLeft.x];
199 for (int x = topLeft.x; x < bottomRight.x; x++, p++) {
200 r += p->r;
201 g += p->g;
202 b += p->b;
203 m += p->m;
204 size++;
205 }
206 }
207
208 if (size)
209 return TPixel32(r / size, g / size, b / size, m / size);
210 else
211 return TPixel32::Transparent;
212 }
213 }
214 return TPixel32::Transparent;
215 }
216
217 //---------------------------------------------------------
218
219 namespace {
220
getAverageColor(const TRect & rect)221 TPixel32 getAverageColor(const TRect &rect) {
222 GLenum fmt =
223 #if defined(TNZ_MACHINE_CHANNEL_ORDER_BGRM)
224 GL_RGBA;
225 #elif defined(TNZ_MACHINE_CHANNEL_ORDER_MBGR)
226 GL_ABGR_EXT;
227 #elif defined(TNZ_MACHINE_CHANNEL_ORDER_RGBM)
228 GL_RGBA;
229 #elif defined(TNZ_MACHINE_CHANNEL_ORDER_MRGB)
230 GL_BGRA;
231 #else
232 // Error PLATFORM NOT SUPPORTED
233 #error "unknown channel order!"
234 #endif
235 UINT r = 0, g = 0, b = 0, m = 0;
236 std::vector<TPixel32> buffer(rect.getLx() * rect.getLy());
237 glReadPixels(rect.x0, rect.y0, rect.getLx(), rect.getLy(), fmt,
238 GL_UNSIGNED_BYTE, &buffer[0]);
239 int size = rect.getLx() * rect.getLy();
240 for (int i = 0; i < size; i++) {
241 r += buffer[i].r;
242 g += buffer[i].g;
243 b += buffer[i].b;
244 }
245
246 return TPixel32(b / size, g / size, r / size, 255);
247 }
248
249 //---------------------------------------------------------
250
getAverageColor(TStroke * stroke)251 TPixel32 getAverageColor(TStroke *stroke) {
252 GLenum fmt =
253 #if defined(TNZ_MACHINE_CHANNEL_ORDER_BGRM)
254 GL_RGBA;
255 #elif defined(TNZ_MACHINE_CHANNEL_ORDER_MBGR)
256 GL_ABGR_EXT;
257 #elif defined(TNZ_MACHINE_CHANNEL_ORDER_RGBM)
258 GL_RGBA;
259 #elif defined(TNZ_MACHINE_CHANNEL_ORDER_MRGB)
260 GL_BGRA;
261 #else
262 // Error PLATFORM NOT SUPPORTED
263 #error "unknown channel order"
264 #endif
265
266 // leggo il buffer e mi prendo i pixels
267 UINT r = 0, g = 0, b = 0, m = 0;
268 TRect rect = convert(stroke->getBBox());
269 std::vector<TPixel32> buffer(rect.getLx() * rect.getLy());
270 glReadPixels(rect.x0, rect.y0, rect.getLx(), rect.getLy(), fmt,
271 GL_UNSIGNED_BYTE, &buffer[0]);
272
273 // calcolo le regioni dello stroke
274 TVectorImage aux;
275 aux.addStroke(stroke);
276 aux.transform(TTranslation(convert(-rect.getP00())));
277 aux.findRegions();
278 int regionCount = aux.getRegionCount();
279 int size = 0, lx = rect.getLx();
280
281 for (int j = 0; j < regionCount; j++) {
282 TRegion *reg = aux.getRegion(j);
283 TRect regRect = convert(reg->getBBox());
284 for (int y = regRect.y0; y < regRect.y1; y++) {
285 std::vector<double> intersections;
286 reg->computeScanlineIntersections(y, intersections);
287 assert(!(intersections.size() & 0x1));
288 for (UINT i = 0; i < intersections.size(); i += 2) {
289 if (intersections[i] == intersections[i + 1]) continue;
290 int firstInters = (int)intersections[i];
291 int secondInters = (int)intersections[i + 1];
292 for (int x = firstInters + 1; x < secondInters - 1; x++) {
293 r += buffer[y * lx + x].r;
294 g += buffer[y * lx + x].g;
295 b += buffer[y * lx + x].b;
296 size++;
297 }
298 }
299 }
300 }
301
302 if (size != 0)
303 return TPixel32(b / size, g / size, r / size, 255);
304 else
305 return TPixel32(buffer[0].b, buffer[0].g, buffer[0].r, 255);
306 }
307
308 } // namespace
309
310 //---------------------------------------------------------
311
pickColor(const TRectD & area) const312 TPixel32 StylePicker::pickColor(const TRectD &area) const {
313 // TRectD rect=area.enlarge(-1,-1);
314 return getAverageColor(convert(area));
315 }
316
317 //---------------------------------------------------------
318
pickColor(TStroke * stroke) const319 TPixel32 StylePicker::pickColor(TStroke *stroke) const {
320 return getAverageColor(stroke);
321 }
322
323 //---------------------------------------------------------
324