Changeset View
Changeset View
Standalone View
Standalone View
imagelib/kpFloodFill.cpp
Show First 20 Lines • Show All 72 Lines • ▼ Show 20 Line(s) | |||||
73 | //--------------------------------------------------------------------- | 73 | //--------------------------------------------------------------------- | ||
74 | 74 | | |||
75 | struct kpFloodFillPrivate | 75 | struct kpFloodFillPrivate | ||
76 | { | 76 | { | ||
77 | // | 77 | // | ||
78 | // Copy of whatever was passed to the constructor. | 78 | // Copy of whatever was passed to the constructor. | ||
79 | // | 79 | // | ||
80 | 80 | | |||
81 | kpImage *imagePtr; | 81 | kpImage *imagePtr{}; | ||
82 | int x, y; | 82 | int x{}, y{}; | ||
83 | kpColor color; | 83 | kpColor color; | ||
84 | int processedColorSimilarity; | 84 | int processedColorSimilarity{}; | ||
85 | 85 | | |||
86 | 86 | | |||
87 | // | 87 | // | ||
88 | // Set by Step 1. | 88 | // Set by Step 1. | ||
89 | // | 89 | // | ||
90 | 90 | | |||
91 | kpColor colorToChange; | 91 | kpColor colorToChange; | ||
92 | 92 | | |||
93 | 93 | | |||
94 | // | 94 | // | ||
95 | // Set by Step 2. | 95 | // Set by Step 2. | ||
96 | // | 96 | // | ||
97 | 97 | | |||
98 | QLinkedList <kpFillLine> fillLines; | 98 | QLinkedList <kpFillLine> fillLines; | ||
99 | QList < QLinkedList <kpFillLine> > fillLinesCache; | 99 | QList < QLinkedList <kpFillLine> > fillLinesCache; | ||
100 | 100 | | |||
101 | QRect boundingRect; | 101 | QRect boundingRect; | ||
102 | 102 | | |||
103 | bool prepared; | 103 | bool prepared{}; | ||
104 | }; | 104 | }; | ||
105 | 105 | | |||
106 | //--------------------------------------------------------------------- | 106 | //--------------------------------------------------------------------- | ||
107 | 107 | | |||
108 | kpFloodFill::kpFloodFill (kpImage *image, int x, int y, | 108 | kpFloodFill::kpFloodFill (kpImage *image, int x, int y, | ||
109 | const kpColor &color, int processedColorSimilarity) | 109 | const kpColor &color, int processedColorSimilarity) | ||
110 | : d (new kpFloodFillPrivate ()) | 110 | : d (new kpFloodFillPrivate ()) | ||
111 | { | 111 | { | ||
Show All 30 Lines | |||||
142 | } | 142 | } | ||
143 | 143 | | |||
144 | //--------------------------------------------------------------------- | 144 | //--------------------------------------------------------------------- | ||
145 | 145 | | |||
146 | // public | 146 | // public | ||
147 | kpCommandSize::SizeType kpFloodFill::size () const | 147 | kpCommandSize::SizeType kpFloodFill::size () const | ||
148 | { | 148 | { | ||
149 | kpCommandSize::SizeType fillLinesCacheSize = 0; | 149 | kpCommandSize::SizeType fillLinesCacheSize = 0; | ||
150 | foreach (const QLinkedList <kpFillLine> &linesList, d->fillLinesCache) | 150 | for (const auto &linesList : d->fillLinesCache) | ||
151 | { | 151 | { | ||
152 | fillLinesCacheSize += ::FillLinesListSize (linesList); | 152 | fillLinesCacheSize += ::FillLinesListSize (linesList); | ||
153 | } | 153 | } | ||
154 | 154 | | |||
155 | return ::FillLinesListSize(d->fillLines) + | 155 | return ::FillLinesListSize(d->fillLines) + | ||
156 | kpCommandSize::QImageSize(d->imagePtr) + | 156 | kpCommandSize::QImageSize(d->imagePtr) + | ||
157 | fillLinesCacheSize; | 157 | fillLinesCacheSize; | ||
158 | } | 158 | } | ||
159 | 159 | | |||
160 | //--------------------------------------------------------------------- | 160 | //--------------------------------------------------------------------- | ||
161 | 161 | | |||
162 | // public | 162 | // public | ||
163 | void kpFloodFill::prepareColorToChange () | 163 | void kpFloodFill::prepareColorToChange () | ||
164 | { | 164 | { | ||
165 | if (d->colorToChange.isValid ()) | 165 | if (d->colorToChange.isValid ()) { | ||
166 | return; | 166 | return; | ||
167 | } | ||||
167 | 168 | | |||
168 | qCDebug(kpLogImagelib) << "kpFloodFill::prepareColorToChange()"; | 169 | qCDebug(kpLogImagelib) << "kpFloodFill::prepareColorToChange()"; | ||
169 | 170 | | |||
170 | d->colorToChange = kpPixmapFX::getColorAtPixel (*d->imagePtr, QPoint (d->x, d->y)); | 171 | d->colorToChange = kpPixmapFX::getColorAtPixel (*d->imagePtr, QPoint (d->x, d->y)); | ||
171 | } | 172 | } | ||
172 | 173 | | |||
173 | //--------------------------------------------------------------------- | 174 | //--------------------------------------------------------------------- | ||
174 | 175 | | |||
175 | // public | 176 | // public | ||
176 | kpColor kpFloodFill::colorToChange () | 177 | kpColor kpFloodFill::colorToChange () | ||
177 | { | 178 | { | ||
178 | prepareColorToChange (); | 179 | prepareColorToChange (); | ||
179 | 180 | | |||
180 | return d->colorToChange; | 181 | return d->colorToChange; | ||
181 | } | 182 | } | ||
182 | 183 | | |||
183 | //--------------------------------------------------------------------- | 184 | //--------------------------------------------------------------------- | ||
184 | 185 | | |||
185 | // Derived from the zSprite2 Graphics Engine | 186 | // Derived from the zSprite2 Graphics Engine | ||
186 | 187 | | |||
187 | // private | 188 | // private | ||
188 | kpColor kpFloodFill::pixelColor (int x, int y, bool *beenHere) const | 189 | kpColor kpFloodFill::pixelColor (int x, int y, bool *beenHere) const | ||
189 | { | 190 | { | ||
190 | if (beenHere) | 191 | if (beenHere) { | ||
191 | *beenHere = false; | 192 | *beenHere = false; | ||
193 | } | ||||
192 | 194 | | |||
193 | Q_ASSERT (y >= 0 && y < static_cast<int> (d->fillLinesCache.count ())); | 195 | Q_ASSERT (y >= 0 && y < static_cast<int> (d->fillLinesCache.count ())); | ||
194 | 196 | | |||
195 | foreach (const kpFillLine &line, d->fillLinesCache [y]) | 197 | for (const auto &line : d->fillLinesCache [y]) | ||
196 | { | 198 | { | ||
197 | if (x >= line.m_x1 && x <= line.m_x2) | 199 | if (x >= line.m_x1 && x <= line.m_x2) | ||
198 | { | 200 | { | ||
199 | if (beenHere) | 201 | if (beenHere) { | ||
200 | *beenHere = true; | 202 | *beenHere = true; | ||
203 | } | ||||
201 | return d->color; | 204 | return d->color; | ||
202 | } | 205 | } | ||
203 | } | 206 | } | ||
204 | 207 | | |||
205 | return kpPixmapFX::getColorAtPixel (*(d->imagePtr), QPoint (x, y)); | 208 | return kpPixmapFX::getColorAtPixel (*(d->imagePtr), QPoint (x, y)); | ||
206 | } | 209 | } | ||
207 | 210 | | |||
208 | //--------------------------------------------------------------------- | 211 | //--------------------------------------------------------------------- | ||
Show All 9 Lines | |||||
218 | 221 | | |||
219 | //--------------------------------------------------------------------- | 222 | //--------------------------------------------------------------------- | ||
220 | 223 | | |||
221 | // private | 224 | // private | ||
222 | int kpFloodFill::findMinX (int y, int x) const | 225 | int kpFloodFill::findMinX (int y, int x) const | ||
223 | { | 226 | { | ||
224 | for (;;) | 227 | for (;;) | ||
225 | { | 228 | { | ||
226 | if (x < 0) | 229 | if (x < 0) { | ||
227 | return 0; | 230 | return 0; | ||
231 | } | ||||
228 | 232 | | |||
229 | if (shouldGoTo (x, y)) | 233 | if (shouldGoTo (x, y)) { | ||
230 | x--; | 234 | x--; | ||
231 | else | 235 | } | ||
236 | else { | ||||
232 | return x + 1; | 237 | return x + 1; | ||
233 | } | 238 | } | ||
234 | } | 239 | } | ||
240 | } | ||||
235 | 241 | | |||
236 | //--------------------------------------------------------------------- | 242 | //--------------------------------------------------------------------- | ||
237 | 243 | | |||
238 | // private | 244 | // private | ||
239 | int kpFloodFill::findMaxX (int y, int x) const | 245 | int kpFloodFill::findMaxX (int y, int x) const | ||
240 | { | 246 | { | ||
241 | for (;;) | 247 | for (;;) | ||
242 | { | 248 | { | ||
243 | if (x > d->imagePtr->width () - 1) | 249 | if (x > d->imagePtr->width () - 1) { | ||
244 | return d->imagePtr->width () - 1; | 250 | return d->imagePtr->width () - 1; | ||
251 | } | ||||
245 | 252 | | |||
246 | if (shouldGoTo (x, y)) | 253 | if (shouldGoTo (x, y)) { | ||
247 | x++; | 254 | x++; | ||
248 | else | 255 | } | ||
256 | else { | ||||
249 | return x - 1; | 257 | return x - 1; | ||
250 | } | 258 | } | ||
251 | } | 259 | } | ||
260 | } | ||||
252 | 261 | | |||
253 | //--------------------------------------------------------------------- | 262 | //--------------------------------------------------------------------- | ||
254 | 263 | | |||
255 | // private | 264 | // private | ||
256 | void kpFloodFill::addLine (int y, int x1, int x2) | 265 | void kpFloodFill::addLine (int y, int x1, int x2) | ||
257 | { | 266 | { | ||
258 | qCDebug(kpLogImagelib) << "kpFillCommand::fillAddLine (" | 267 | qCDebug(kpLogImagelib) << "kpFillCommand::fillAddLine (" | ||
259 | << y << "," << x1 << "," << x2 << ")"; | 268 | << y << "," << x1 << "," << x2 << ")"; | ||
260 | 269 | | |||
261 | d->fillLines.append (kpFillLine (y, x1, x2)); | 270 | d->fillLines.append (kpFillLine (y, x1, x2)); | ||
262 | d->fillLinesCache [y].append ( | 271 | d->fillLinesCache [y].append ( | ||
263 | kpFillLine (y/*OPT: can determine from array index*/, x1, x2)); | 272 | kpFillLine (y/*OPT: can determine from array index*/, x1, x2)); | ||
264 | d->boundingRect = d->boundingRect.united (QRect (QPoint (x1, y), QPoint (x2, y))); | 273 | d->boundingRect = d->boundingRect.united (QRect (QPoint (x1, y), QPoint (x2, y))); | ||
265 | } | 274 | } | ||
266 | 275 | | |||
267 | //--------------------------------------------------------------------- | 276 | //--------------------------------------------------------------------- | ||
268 | 277 | | |||
269 | // private | 278 | // private | ||
270 | void kpFloodFill::findAndAddLines (const kpFillLine &fillLine, int dy) | 279 | void kpFloodFill::findAndAddLines (const kpFillLine &fillLine, int dy) | ||
271 | { | 280 | { | ||
272 | // out of bounds? | 281 | // out of bounds? | ||
273 | if (fillLine.m_y + dy < 0 || fillLine.m_y + dy >= d->imagePtr->height ()) | 282 | if (fillLine.m_y + dy < 0 || fillLine.m_y + dy >= d->imagePtr->height ()) { | ||
274 | return; | 283 | return; | ||
284 | } | ||||
275 | 285 | | |||
276 | for (int xnow = fillLine.m_x1; xnow <= fillLine.m_x2; xnow++) | 286 | for (int xnow = fillLine.m_x1; xnow <= fillLine.m_x2; xnow++) | ||
277 | { | 287 | { | ||
278 | // At current position, right colour? | 288 | // At current position, right colour? | ||
279 | if (shouldGoTo (xnow, fillLine.m_y + dy)) | 289 | if (shouldGoTo (xnow, fillLine.m_y + dy)) | ||
280 | { | 290 | { | ||
281 | // Find minimum and maximum x values | 291 | // Find minimum and maximum x values | ||
282 | int minxnow = findMinX (fillLine.m_y + dy, xnow); | 292 | int minxnow = findMinX (fillLine.m_y + dy, xnow); | ||
283 | int maxxnow = findMaxX (fillLine.m_y + dy, xnow); | 293 | int maxxnow = findMaxX (fillLine.m_y + dy, xnow); | ||
284 | 294 | | |||
285 | // Draw line | 295 | // Draw line | ||
286 | addLine (fillLine.m_y + dy, minxnow, maxxnow); | 296 | addLine (fillLine.m_y + dy, minxnow, maxxnow); | ||
287 | 297 | | |||
288 | // Move x pointer | 298 | // Move x pointer | ||
289 | xnow = maxxnow; | 299 | xnow = maxxnow; | ||
290 | } | 300 | } | ||
291 | } | 301 | } | ||
292 | } | 302 | } | ||
293 | 303 | | |||
294 | //--------------------------------------------------------------------- | 304 | //--------------------------------------------------------------------- | ||
295 | 305 | | |||
296 | // public | 306 | // public | ||
297 | void kpFloodFill::prepare () | 307 | void kpFloodFill::prepare () | ||
298 | { | 308 | { | ||
299 | if (d->prepared) | 309 | if (d->prepared) { | ||
300 | return; | 310 | return; | ||
311 | } | ||||
301 | 312 | | |||
302 | qCDebug(kpLogImagelib) << "kpFloodFill::prepare()"; | 313 | qCDebug(kpLogImagelib) << "kpFloodFill::prepare()"; | ||
303 | 314 | | |||
304 | prepareColorToChange (); | 315 | prepareColorToChange (); | ||
305 | 316 | | |||
306 | d->boundingRect = QRect (); | 317 | d->boundingRect = QRect (); | ||
307 | 318 | | |||
308 | qCDebug(kpLogImagelib) << "\tperforming NOP check"; | 319 | qCDebug(kpLogImagelib) << "\tperforming NOP check"; | ||
309 | 320 | | |||
310 | // get the color we need to replace | 321 | // get the color we need to replace | ||
311 | if (d->processedColorSimilarity == 0 && d->color == d->colorToChange) | 322 | if (d->processedColorSimilarity == 0 && d->color == d->colorToChange) | ||
312 | { | 323 | { | ||
313 | // need to do absolutely nothing (this is a significant optimization | 324 | // need to do absolutely nothing (this is a significant optimization | ||
314 | // for people who randomly click a lot over already-filled areas) | 325 | // for people who randomly click a lot over already-filled areas) | ||
315 | d->prepared = true; // sync with all "return true"'s | 326 | d->prepared = true; // sync with all "return true"'s | ||
316 | return; | 327 | return; | ||
317 | } | 328 | } | ||
318 | 329 | | |||
319 | qCDebug(kpLogImagelib) << "\tcreating fillLinesCache"; | 330 | qCDebug(kpLogImagelib) << "\tcreating fillLinesCache"; | ||
320 | 331 | | |||
321 | // ready cache | 332 | // ready cache | ||
322 | for (int i = 0; i < d->imagePtr->height (); i++) | 333 | for (int i = 0; i < d->imagePtr->height (); i++) { | ||
323 | d->fillLinesCache.append (QLinkedList <kpFillLine> ()); | 334 | d->fillLinesCache.append (QLinkedList <kpFillLine> ()); | ||
335 | } | ||||
324 | 336 | | |||
325 | qCDebug(kpLogImagelib) << "\tcreating fill lines"; | 337 | qCDebug(kpLogImagelib) << "\tcreating fill lines"; | ||
326 | 338 | | |||
327 | // draw initial line | 339 | // draw initial line | ||
328 | addLine (d->y, findMinX (d->y, d->x), findMaxX (d->y, d->x)); | 340 | addLine (d->y, findMinX (d->y, d->x), findMaxX (d->y, d->x)); | ||
329 | 341 | | |||
330 | for (QLinkedList <kpFillLine>::ConstIterator it = d->fillLines.begin (); | 342 | for (QLinkedList <kpFillLine>::ConstIterator it = d->fillLines.begin (); | ||
331 | it != d->fillLines.end (); | 343 | it != d->fillLines.end (); | ||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Line(s) | 384 | { | |||
373 | prepare(); | 385 | prepare(); | ||
374 | 386 | | |||
375 | QApplication::setOverrideCursor(Qt::WaitCursor); | 387 | QApplication::setOverrideCursor(Qt::WaitCursor); | ||
376 | 388 | | |||
377 | QPainter painter(d->imagePtr); | 389 | QPainter painter(d->imagePtr); | ||
378 | 390 | | |||
379 | // by definition, flood fill with a fully transparent color erases the pixels | 391 | // by definition, flood fill with a fully transparent color erases the pixels | ||
380 | // and sets them to be fully transparent | 392 | // and sets them to be fully transparent | ||
381 | if ( d->color.isTransparent() ) | 393 | if ( d->color.isTransparent() ) { | ||
382 | painter.setCompositionMode(QPainter::CompositionMode_Clear); | 394 | painter.setCompositionMode(QPainter::CompositionMode_Clear); | ||
395 | } | ||||
383 | 396 | | |||
384 | painter.setPen(d->color.toQColor()); | 397 | painter.setPen(d->color.toQColor()); | ||
385 | 398 | | |||
386 | foreach (const kpFillLine &l, d->fillLines) | 399 | for (const auto &l : d->fillLines) | ||
387 | { | 400 | { | ||
388 | if ( l.m_x1 == l.m_x2 ) | 401 | if ( l.m_x1 == l.m_x2 ) { | ||
389 | painter.drawPoint(l.m_x1, l.m_y); | 402 | painter.drawPoint(l.m_x1, l.m_y); | ||
390 | else | 403 | } | ||
404 | else { | ||||
391 | painter.drawLine(l.m_x1, l.m_y, l.m_x2, l.m_y); | 405 | painter.drawLine(l.m_x1, l.m_y, l.m_x2, l.m_y); | ||
392 | } | 406 | } | ||
407 | } | ||||
393 | 408 | | |||
394 | QApplication::restoreOverrideCursor(); | 409 | QApplication::restoreOverrideCursor(); | ||
395 | } | 410 | } | ||
396 | 411 | | |||
397 | //--------------------------------------------------------------------- | 412 | //--------------------------------------------------------------------- |