File: | home/HaikuArchives/ArtPaint/artpaint/tools/FillTool.cpp |
Warning: | line 1184, column 2 Value stored to 'y_gradient' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright 2003, Heikki Suhonen |
3 | * Copyright 2009, Karsten Heimrich |
4 | * Distributed under the terms of the MIT License. |
5 | * |
6 | * Authors: |
7 | * Heikki Suhonen <heikki.suhonen@gmail.com> |
8 | * Karsten Heimrich <host.haiku@gmx.de> |
9 | * Dale Cieslak <dcieslak@yahoo.com> |
10 | * |
11 | */ |
12 | |
13 | #include "FillTool.h" |
14 | |
15 | #include "BitmapDrawer.h" |
16 | #include "ColorPalette.h" |
17 | #include "ColorView.h" |
18 | #include "Cursors.h" |
19 | #include "Image.h" |
20 | #include "ImageView.h" |
21 | #include "NumberSliderControl.h" |
22 | #include "PaintApplication.h" |
23 | #include "PixelOperations.h" |
24 | #include "Selection.h" |
25 | #include "ToolScript.h" |
26 | #include "UtilityClasses.h" |
27 | |
28 | |
29 | #include <Catalog.h> |
30 | #include <CheckBox.h> |
31 | #include <Control.h> |
32 | #include <File.h> |
33 | #include <GridLayoutBuilder.h> |
34 | #include <GroupLayoutBuilder.h> |
35 | #include <SeparatorView.h> |
36 | |
37 | |
38 | #include <stdlib.h> |
39 | #include <string.h> |
40 | |
41 | |
42 | #undef B_TRANSLATION_CONTEXT"Tools" |
43 | #define B_TRANSLATION_CONTEXT"Tools" "Tools" |
44 | |
45 | |
46 | using ArtPaint::Interface::NumberSliderControl; |
47 | |
48 | |
49 | FillTool::FillTool() |
50 | : DrawingTool(B_TRANSLATE("Fill tool")BLocaleRoster::Default()->GetCatalog()->GetString(("Fill tool" ), "Tools"), FILL_TOOL) |
51 | { |
52 | // Set options here. The MODE_OPTION is used for determining if we do flood |
53 | // fill or some other type of fill. |
54 | fOptions = GRADIENT_ENABLED_OPTION | PREVIEW_ENABLED_OPTION |
55 | | TOLERANCE_OPTION | MODE_OPTION; |
56 | fOptionsCount = 4; |
57 | binary_fill_map = NULL__null; |
58 | |
59 | // Initially disable the gradient. |
60 | SetOption(GRADIENT_ENABLED_OPTION, B_CONTROL_OFF); |
61 | // Initially enable the preview. |
62 | SetOption(PREVIEW_ENABLED_OPTION,B_CONTROL_ON); |
63 | SetOption(TOLERANCE_OPTION,0); |
64 | SetOption(MODE_OPTION,B_CONTROL_ON); |
65 | |
66 | gradient_color1 = 0x00000000; |
67 | gradient_color2 = 0xFFFFFFFF; |
68 | } |
69 | |
70 | |
71 | FillTool::~FillTool() |
72 | { |
73 | } |
74 | |
75 | |
76 | ToolScript* |
77 | FillTool::UseTool(ImageView *view, uint32 buttons, BPoint point, BPoint viewPoint) |
78 | { |
79 | ToolScript* toolScript = new ToolScript(Type(), fToolSettings, |
80 | ((PaintApplication*)be_app)->Color(true)); |
81 | toolScript->AddPoint(point); |
82 | |
83 | Selection* selection = view->GetSelection(); |
84 | selection = (selection->IsEmpty() ? NULL__null : selection); |
85 | |
86 | if (fToolSettings.gradient_enabled == B_CONTROL_ON) { |
87 | // Do just a fill with gradient |
88 | toolScript->AddPoint(GradientFill(view, buttons, point, viewPoint, |
89 | selection)); |
90 | } else { |
91 | // Do just a normal fill without gradient |
92 | NormalFill(view, buttons, point, selection); |
93 | } |
94 | |
95 | return toolScript; |
96 | } |
97 | |
98 | |
99 | int32 |
100 | FillTool::UseToolWithScript(ToolScript*, BBitmap*) |
101 | { |
102 | return B_OK((int)0); |
103 | } |
104 | |
105 | |
106 | BView* |
107 | FillTool::ConfigView() |
108 | { |
109 | return new FillToolConfigView(this, gradient_color1, gradient_color2); |
110 | } |
111 | |
112 | |
113 | status_t |
114 | FillTool::NormalFill(ImageView* view, uint32 buttons, BPoint start, Selection* sel) |
115 | { |
116 | // Get the necessary parameters |
117 | BWindow *window = view->Window(); |
118 | if (window == NULL__null) |
119 | return B_ERROR(-1); |
120 | |
121 | uint32 tolerance = (uint32)((float)fToolSettings.tolerance/100.0 * 255); |
122 | |
123 | filled_bitmap = view->ReturnImage()->ReturnActiveBitmap(); |
124 | BitmapDrawer *drawer = new BitmapDrawer(filled_bitmap); |
125 | BRect bitmap_bounds = filled_bitmap->Bounds(); |
126 | bitmap_bounds.OffsetTo(BPoint(0,0)); |
127 | |
128 | // Get the color for the fill. |
129 | rgb_color c = ((PaintApplication*)be_app)->Color(TRUE1); |
130 | uint32 color = RGBColorToBGRA(c); |
131 | |
132 | // Get the old color. |
133 | uint32 old_color = drawer->GetPixel(start); |
134 | |
135 | // If the old color is the same as new and the tolerance is 0, we should do nothing. |
136 | if ( (old_color == color) && (tolerance == 0) ) { |
137 | delete drawer; |
138 | return B_OK((int)0); |
139 | } |
140 | |
141 | // These are the edge coordinates of bitmap. It is still safe to |
142 | // address a pixel at max_x,max_y or min_x,min_y. |
143 | int32 min_x,min_y,max_x,max_y; |
144 | min_x = (int32)bitmap_bounds.left; |
145 | min_y = (int32)bitmap_bounds.top; |
146 | max_x = (int32)bitmap_bounds.right; |
147 | max_y = (int32)bitmap_bounds.bottom; |
148 | |
149 | if (bitmap_bounds.Contains(start) == TRUE1) { |
150 | if (fToolSettings.mode == B_CONTROL_ON) { // Do the flood fill |
151 | // Here fill the area using drawer's SetPixel and GetPixel. |
152 | // The algorithm uses 4-connected version of flood-fill. |
153 | // The SetPixel and GetPixel functions are versions that |
154 | // do not check bounds so we have to be careful not to exceed |
155 | // bitmap's bounds. |
156 | if (tolerance != 0) { |
157 | binary_fill_map = new BBitmap(filled_bitmap->Bounds(), B_GRAY1); |
158 | // Clear the binary map. |
159 | uchar *binary_bits = (uchar*)binary_fill_map->Bits(); |
160 | uint32 binary_bitslength = binary_fill_map->BitsLength(); |
161 | for (uint32 i = 0; i < binary_bitslength; i++) |
162 | *binary_bits++ = 0x00; |
163 | } |
164 | |
165 | PointStack stack; |
166 | stack.Push(start); |
167 | |
168 | while (!stack.IsEmpty()) { |
169 | BPoint span_start = stack.Pop(); |
170 | if ( (span_start.y == min_y) && (min_y != max_y) ) { |
171 | // Only check the spans below this line |
172 | CheckLowerSpans(span_start, drawer, stack, min_x, max_x, |
173 | color, old_color, tolerance, sel); |
174 | } |
175 | else if ( (span_start.y == max_y) && (min_y != max_y) ) { |
176 | // Only check the spans above this line. |
177 | CheckUpperSpans(span_start, drawer, stack, min_x, max_x, |
178 | color, old_color, tolerance, sel); |
179 | } |
180 | else if (min_y != max_y) { |
181 | // Check the spans above and below this line. |
182 | CheckBothSpans(span_start, drawer, stack, min_x, max_x, |
183 | color, old_color, tolerance, sel); |
184 | } |
185 | else { |
186 | // The image is only one pixel high. Fill the only span. |
187 | FillSpan(span_start, drawer, min_x, max_x, color, old_color, |
188 | tolerance, sel); |
189 | } |
190 | } |
191 | if (tolerance != 0) { |
192 | delete binary_fill_map; |
193 | binary_fill_map = NULL__null; |
194 | } |
195 | } |
196 | else { // Fill all the pixels that are within the tolerance. |
197 | if ((sel == NULL__null) || (sel->IsEmpty() == true)) { |
198 | for (int32 y=min_y;y<=max_y;y++) { |
199 | for (int32 x=min_x;x<=max_x;x++) { |
200 | if (compare_2_pixels_with_variance(old_color,drawer->GetPixel(x,y),tolerance)) { |
201 | drawer->SetPixel(x,y,color); |
202 | } |
203 | } |
204 | } |
205 | } |
206 | else { |
207 | for (int32 y=min_y;y<=max_y;y++) { |
208 | for (int32 x=min_x;x<=max_x;x++) { |
209 | if (sel->ContainsPoint(x,y) && compare_2_pixels_with_variance(old_color,drawer->GetPixel(x,y),tolerance)) { |
210 | drawer->SetPixel(x,y,color); |
211 | } |
212 | } |
213 | } |
214 | } |
215 | } |
216 | |
217 | SetLastUpdatedRect(filled_bitmap->Bounds()); |
218 | window->Lock(); |
219 | view->UpdateImage(LastUpdatedRect()); |
220 | view->Sync(); |
221 | window->Unlock(); |
222 | } |
223 | delete drawer; |
224 | return B_OK((int)0); |
225 | } |
226 | |
227 | |
228 | void |
229 | FillTool::CheckLowerSpans(BPoint span_start,BitmapDrawer *drawer,PointStack &stack,int32 min_x,int32 max_x,uint32 new_color,uint32 old_color,int32 tolerance,Selection *sel) |
230 | { |
231 | // First get the vital data. |
232 | int32 x,start_x; |
233 | int32 y = (int32)span_start.y; |
234 | x = start_x = (int32)span_start.x; |
235 | bool inside_lower_span = FALSE0; |
236 | |
237 | if ((sel == NULL__null) || (sel->IsEmpty() == TRUE1)) { |
238 | if ((tolerance == 0) && (binary_fill_map == NULL__null)) { |
239 | // Then go from start towards the left side of the bitmap. |
240 | while ( (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) { |
241 | drawer->SetPixel(x,y,new_color); |
242 | if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) ) { |
243 | stack.Push(BPoint(x,y+1)); |
244 | inside_lower_span = TRUE1; |
245 | } |
246 | else if ( (inside_lower_span == TRUE1) && (drawer->GetPixel(x,y+1) != old_color) ) { |
247 | inside_lower_span = FALSE0; |
248 | } |
249 | x--; |
250 | } |
251 | |
252 | // Then go from start_x+1 towards the right side of the bitmap. |
253 | // We might already be inside a lower span |
254 | inside_lower_span = ( drawer->GetPixel(start_x,y+1) == old_color ); |
255 | x = start_x + 1; |
256 | while ( (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) { |
257 | drawer->SetPixel(x,y,new_color); |
258 | if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) ) { |
259 | stack.Push(BPoint(x,y+1)); |
260 | inside_lower_span = TRUE1; |
261 | } |
262 | else if ( (inside_lower_span == TRUE1) && (drawer->GetPixel(x,y+1) != old_color) ) { |
263 | inside_lower_span = FALSE0; |
264 | } |
265 | x++; |
266 | } |
267 | } |
268 | else { |
269 | // This is the case that takes the variance into account. We must use a |
270 | // binary bitmap to see what parts have already been filled. |
271 | uint32 binary_bpr = binary_fill_map->BytesPerRow(); |
272 | uchar *binary_bits = (uchar*)binary_fill_map->Bits(); |
273 | // Then go from start towards the left side of the bitmap. |
274 | while ( (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) { |
275 | drawer->SetPixel(x,y,new_color); |
276 | // *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8)); |
277 | *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8)); |
278 | if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) { |
279 | stack.Push(BPoint(x,y+1)); |
280 | inside_lower_span = TRUE1; |
281 | } |
282 | else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) { |
283 | inside_lower_span = FALSE0; |
284 | } |
285 | x--; |
286 | } |
287 | |
288 | // Then go from start_x+1 towards the right side of the bitmap. |
289 | // We might already be inside a lower span |
290 | inside_lower_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y+1),old_color,tolerance) ); |
291 | x = start_x + 1; |
292 | while ( (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) { |
293 | drawer->SetPixel(x,y,new_color); |
294 | // *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8)); |
295 | *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8)); |
296 | if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) { |
297 | stack.Push(BPoint(x,y+1)); |
298 | inside_lower_span = TRUE1; |
299 | } |
300 | else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) { |
301 | inside_lower_span = FALSE0; |
302 | } |
303 | x++; |
304 | } |
305 | } |
306 | } |
307 | else { |
308 | if ((tolerance == 0) && (binary_fill_map == NULL__null)) { |
309 | // Then go from start towards the left side of the bitmap. |
310 | while (sel->ContainsPoint(x,y) && (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) { |
311 | drawer->SetPixel(x,y,new_color); |
312 | if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) && sel->ContainsPoint(x,y+1)) { |
313 | stack.Push(BPoint(x,y+1)); |
314 | inside_lower_span = TRUE1; |
315 | } |
316 | else if ( (inside_lower_span == TRUE1) && ((drawer->GetPixel(x,y+1) != old_color) || !sel->ContainsPoint(x,y+1))) { |
317 | inside_lower_span = FALSE0; |
318 | } |
319 | x--; |
320 | } |
321 | |
322 | // Then go from start_x+1 towards the right side of the bitmap. |
323 | // We might already be inside a lower span |
324 | inside_lower_span = ( drawer->GetPixel(start_x,y+1) == old_color ) && sel->ContainsPoint(start_x,y+1); |
325 | x = start_x + 1; |
326 | while (sel->ContainsPoint(x,y) && (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) { |
327 | drawer->SetPixel(x,y,new_color); |
328 | if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) && sel->ContainsPoint(x,y+1)) { |
329 | stack.Push(BPoint(x,y+1)); |
330 | inside_lower_span = TRUE1; |
331 | } |
332 | else if ( (inside_lower_span == TRUE1) && ((drawer->GetPixel(x,y+1) != old_color) || !sel->ContainsPoint(x,y+1))) { |
333 | inside_lower_span = FALSE0; |
334 | } |
335 | x++; |
336 | } |
337 | } |
338 | else { |
339 | // This is the case that takes the variance into account. We must use a |
340 | // binary bitmap to see what parts have already been filled. |
341 | uint32 binary_bpr = binary_fill_map->BytesPerRow(); |
342 | uchar *binary_bits = (uchar*)binary_fill_map->Bits(); |
343 | // Then go from start towards the left side of the bitmap. |
344 | while (sel->ContainsPoint(x,y) && (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) { |
345 | drawer->SetPixel(x,y,new_color); |
346 | *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8)); |
347 | if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) && sel->ContainsPoint(x,y+1) ) { |
348 | stack.Push(BPoint(x,y+1)); |
349 | inside_lower_span = TRUE1; |
350 | } |
351 | else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance) || !sel->ContainsPoint(x,y+1)) ) { |
352 | inside_lower_span = FALSE0; |
353 | } |
354 | x--; |
355 | } |
356 | |
357 | // Then go from start_x+1 towards the right side of the bitmap. |
358 | // We might already be inside a lower span |
359 | inside_lower_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y+1),old_color,tolerance) && sel->ContainsPoint(start_x,y+1)); |
360 | x = start_x + 1; |
361 | while (sel->ContainsPoint(x,y) && (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) { |
362 | drawer->SetPixel(x,y,new_color); |
363 | *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8)); |
364 | if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) && sel->ContainsPoint(x,y+1) ) { |
365 | stack.Push(BPoint(x,y+1)); |
366 | inside_lower_span = TRUE1; |
367 | } |
368 | else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance) || !sel->ContainsPoint(x,y+1)) ) { |
369 | inside_lower_span = FALSE0; |
370 | } |
371 | x++; |
372 | } |
373 | } |
374 | } |
375 | } |
376 | |
377 | void FillTool::CheckUpperSpans(BPoint span_start,BitmapDrawer *drawer,PointStack &stack,int32 min_x,int32 max_x,uint32 new_color,uint32 old_color,int32 tolerance,Selection *sel) |
378 | { |
379 | // First get the vital data. |
380 | int32 x,start_x; |
381 | int32 y = (int32)span_start.y; |
382 | x = start_x = (int32)span_start.x; |
383 | bool inside_upper_span = FALSE0; |
384 | |
385 | if ((sel == NULL__null) || (sel->IsEmpty() == TRUE1)) { |
386 | if ((tolerance == 0) && (binary_fill_map == NULL__null)) { |
387 | // Then go from start towards the left side of the bitmap. |
388 | while ( (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) { |
389 | drawer->SetPixel(x,y,new_color); |
390 | if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) ) { |
391 | stack.Push(BPoint(x,y-1)); |
392 | inside_upper_span = TRUE1; |
393 | } |
394 | else if ( (inside_upper_span == TRUE1) && (drawer->GetPixel(x,y-1) != old_color) ) { |
395 | inside_upper_span = FALSE0; |
396 | } |
397 | x--; |
398 | } |
399 | |
400 | // Then go from start_x+1 towards the right side of the bitmap. |
401 | // We might already be inside a lower span |
402 | inside_upper_span = ( drawer->GetPixel(start_x,y-1) == old_color ); |
403 | x = start_x + 1; |
404 | while ( (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) { |
405 | drawer->SetPixel(x,y,new_color); |
406 | if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) ) { |
407 | stack.Push(BPoint(x,y-1)); |
408 | inside_upper_span = TRUE1; |
409 | } |
410 | else if ( (inside_upper_span == TRUE1) && (drawer->GetPixel(x,y-1) != old_color) ) { |
411 | inside_upper_span = FALSE0; |
412 | } |
413 | x++; |
414 | } |
415 | } |
416 | else { |
417 | // This is the case that takes the variance into account. We must use a |
418 | // binary bitmap to see what parts have already been filled. |
419 | uint32 binary_bpr = binary_fill_map->BytesPerRow(); |
420 | uchar *binary_bits = (uchar*)binary_fill_map->Bits(); |
421 | |
422 | // Then go from start towards the left side of the bitmap. |
423 | while ( (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) { |
424 | drawer->SetPixel(x,y,new_color); |
425 | // *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8)); |
426 | *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8)); |
427 | if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) ) { |
428 | stack.Push(BPoint(x,y-1)); |
429 | inside_upper_span = TRUE1; |
430 | } |
431 | else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1), old_color,tolerance)) ) { |
432 | inside_upper_span = FALSE0; |
433 | } |
434 | x--; |
435 | } |
436 | |
437 | // Then go from start_x+1 towards the right side of the bitmap. |
438 | // We might already be inside a lower span |
439 | inside_upper_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y-1) , old_color,tolerance) ); |
440 | x = start_x + 1; |
441 | while ( (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y), old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) { |
442 | drawer->SetPixel(x,y,new_color); |
443 | // *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8)); |
444 | *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8)); |
445 | if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) ) { |
446 | stack.Push(BPoint(x,y-1)); |
447 | inside_upper_span = TRUE1; |
448 | } |
449 | else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) ) { |
450 | inside_upper_span = FALSE0; |
451 | } |
452 | x++; |
453 | } |
454 | } |
455 | } |
456 | else { |
457 | if ((tolerance == 0) && (binary_fill_map == NULL__null)) { |
458 | // Then go from start towards the left side of the bitmap. |
459 | while (sel->ContainsPoint(x,y) && (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) { |
460 | drawer->SetPixel(x,y,new_color); |
461 | if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) && sel->ContainsPoint(x,y-1) ) { |
462 | stack.Push(BPoint(x,y-1)); |
463 | inside_upper_span = TRUE1; |
464 | } |
465 | else if ( (inside_upper_span == TRUE1) && ((drawer->GetPixel(x,y-1) != old_color) || !sel->ContainsPoint(x,y-1)) ) { |
466 | inside_upper_span = FALSE0; |
467 | } |
468 | x--; |
469 | } |
470 | |
471 | // Then go from start_x+1 towards the right side of the bitmap. |
472 | // We might already be inside a lower span |
473 | inside_upper_span = ( drawer->GetPixel(start_x,y-1) == old_color ) && sel->ContainsPoint(start_x,y-1); |
474 | x = start_x + 1; |
475 | while (sel->ContainsPoint(x,y) && (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) { |
476 | drawer->SetPixel(x,y,new_color); |
477 | if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) && sel->ContainsPoint(x,y-1)) { |
478 | stack.Push(BPoint(x,y-1)); |
479 | inside_upper_span = TRUE1; |
480 | } |
481 | else if ( (inside_upper_span == TRUE1) && ((drawer->GetPixel(x,y-1) != old_color) || !sel->ContainsPoint(x,y-1)) ) { |
482 | inside_upper_span = FALSE0; |
483 | } |
484 | x++; |
485 | } |
486 | } |
487 | else { |
488 | // This is the case that takes the variance into account. We must use a |
489 | // binary bitmap to see what parts have already been filled. |
490 | uint32 binary_bpr = binary_fill_map->BytesPerRow(); |
491 | uchar *binary_bits = (uchar*)binary_fill_map->Bits(); |
492 | |
493 | // Then go from start towards the left side of the bitmap. |
494 | while (sel->ContainsPoint(x,y) && (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) { |
495 | drawer->SetPixel(x,y,new_color); |
496 | *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8)); |
497 | if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) && sel->ContainsPoint(x,y-1) ) { |
498 | stack.Push(BPoint(x,y-1)); |
499 | inside_upper_span = TRUE1; |
500 | } |
501 | else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1), old_color,tolerance) || !sel->ContainsPoint(x,y-1)) ) { |
502 | inside_upper_span = FALSE0; |
503 | } |
504 | x--; |
505 | } |
506 | |
507 | // Then go from start_x+1 towards the right side of the bitmap. |
508 | // We might already be inside a lower span |
509 | inside_upper_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y-1) , old_color,tolerance) && sel->ContainsPoint(start_x,y-1)); |
510 | x = start_x + 1; |
511 | while (sel->ContainsPoint(x,y) && (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y), old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) { |
512 | drawer->SetPixel(x,y,new_color); |
513 | *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8)); |
514 | if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) && sel->ContainsPoint(x,y-1) ) { |
515 | stack.Push(BPoint(x,y-1)); |
516 | inside_upper_span = TRUE1; |
517 | } |
518 | else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance) || !sel->ContainsPoint(x,y-1)) ) { |
519 | inside_upper_span = FALSE0; |
520 | } |
521 | x++; |
522 | } |
523 | } |
524 | } |
525 | } |
526 | |
527 | void |
528 | FillTool::CheckBothSpans(BPoint span_start,BitmapDrawer *drawer,PointStack &stack,int32 min_x,int32 max_x,uint32 new_color,uint32 old_color,int32 tolerance,Selection *sel) |
529 | { |
530 | // First get the vital data. |
531 | int32 x,start_x; |
532 | int32 y = (int32)span_start.y; |
533 | x = start_x = (int32)span_start.x; |
534 | bool inside_lower_span = FALSE0; |
535 | bool inside_upper_span = FALSE0; |
536 | |
537 | if ((sel == NULL__null) || (sel->IsEmpty() == TRUE1)) { |
538 | if ((tolerance == 0) && (binary_fill_map == NULL__null)) { |
539 | // Then go from start towards the left side of the bitmap. |
540 | while ( (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) { |
541 | drawer->SetPixel(x,y,new_color); |
542 | |
543 | if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) ) { |
544 | stack.Push(BPoint(x,y+1)); |
545 | inside_lower_span = TRUE1; |
546 | } |
547 | else if ( (inside_lower_span == TRUE1) && (drawer->GetPixel(x,y+1) != old_color) ) { |
548 | inside_lower_span = FALSE0; |
549 | } |
550 | |
551 | if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) ) { |
552 | stack.Push(BPoint(x,y-1)); |
553 | inside_upper_span = TRUE1; |
554 | } |
555 | else if ( (inside_upper_span == TRUE1) && (drawer->GetPixel(x,y-1) != old_color) ) { |
556 | inside_upper_span = FALSE0; |
557 | } |
558 | |
559 | x--; |
560 | } |
561 | |
562 | // Then go from start_x+1 towards the right side of the bitmap. |
563 | // We might already be inside a lower span |
564 | inside_lower_span = ( drawer->GetPixel(start_x,y+1) == old_color ); |
565 | inside_upper_span = ( drawer->GetPixel(start_x,y-1) == old_color ); |
566 | x = start_x + 1; |
567 | while ( (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) { |
568 | drawer->SetPixel(x,y,new_color); |
569 | |
570 | if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) ) { |
571 | stack.Push(BPoint(x,y+1)); |
572 | inside_lower_span = TRUE1; |
573 | } |
574 | else if ( (inside_lower_span == TRUE1) && (drawer->GetPixel(x,y+1) != old_color) ) { |
575 | inside_lower_span = FALSE0; |
576 | } |
577 | |
578 | if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) ) { |
579 | stack.Push(BPoint(x,y-1)); |
580 | inside_upper_span = TRUE1; |
581 | } |
582 | else if ( (inside_upper_span == TRUE1) && (drawer->GetPixel(x,y-1) != old_color) ) { |
583 | inside_upper_span = FALSE0; |
584 | } |
585 | |
586 | x++; |
587 | } |
588 | } |
589 | else { |
590 | // This is the case that takes the variance into account. We must use a |
591 | // binary bitmap to see what parts have already been filled. |
592 | uint32 binary_bpr = binary_fill_map->BytesPerRow(); |
593 | uchar *binary_bits = (uchar*)binary_fill_map->Bits(); |
594 | |
595 | // Then go from start towards the left side of the bitmap. |
596 | while ( (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y), old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) { |
597 | drawer->SetPixel(x,y,new_color); |
598 | // *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8)); |
599 | *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8)); |
600 | |
601 | if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) { |
602 | stack.Push(BPoint(x,y+1)); |
603 | inside_lower_span = TRUE1; |
604 | } |
605 | else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) { |
606 | inside_lower_span = FALSE0; |
607 | } |
608 | |
609 | if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) ) { |
610 | stack.Push(BPoint(x,y-1)); |
611 | inside_upper_span = TRUE1; |
612 | } |
613 | else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1), old_color,tolerance)) ) { |
614 | inside_upper_span = FALSE0; |
615 | } |
616 | |
617 | x--; |
618 | } |
619 | |
620 | // Then go from start_x+1 towards the right side of the bitmap. |
621 | // We might already be inside a lower span |
622 | inside_lower_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y+1),old_color,tolerance) ); |
623 | inside_upper_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y-1), old_color,tolerance) ); |
624 | x = start_x + 1; |
625 | while ( (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) { |
626 | drawer->SetPixel(x,y,new_color); |
627 | // *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8)); |
628 | *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8)); |
629 | |
630 | if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) { |
631 | stack.Push(BPoint(x,y+1)); |
632 | inside_lower_span = TRUE1; |
633 | } |
634 | else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) ) { |
635 | inside_lower_span = FALSE0; |
636 | } |
637 | |
638 | if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1), old_color,tolerance)) ) { |
639 | stack.Push(BPoint(x,y-1)); |
640 | inside_upper_span = TRUE1; |
641 | } |
642 | else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) ) { |
643 | inside_upper_span = FALSE0; |
644 | } |
645 | |
646 | x++; |
647 | } |
648 | } |
649 | } |
650 | else { |
651 | if ((tolerance == 0) && (binary_fill_map == NULL__null)) { |
652 | // Then go from start towards the left side of the bitmap. |
653 | while (sel->ContainsPoint(x,y) && (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) { |
654 | drawer->SetPixel(x,y,new_color); |
655 | |
656 | if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) && sel->ContainsPoint(x,y+1)) { |
657 | stack.Push(BPoint(x,y+1)); |
658 | inside_lower_span = TRUE1; |
659 | } |
660 | else if ( (inside_lower_span == TRUE1) && ((drawer->GetPixel(x,y+1) != old_color) || !sel->ContainsPoint(x,y+1)) ) { |
661 | inside_lower_span = FALSE0; |
662 | } |
663 | |
664 | if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) && sel->ContainsPoint(x,y-1)) { |
665 | stack.Push(BPoint(x,y-1)); |
666 | inside_upper_span = TRUE1; |
667 | } |
668 | else if ( (inside_upper_span == TRUE1) && ((drawer->GetPixel(x,y-1) != old_color) || !sel->ContainsPoint(x,y-1))) { |
669 | inside_upper_span = FALSE0; |
670 | } |
671 | |
672 | x--; |
673 | } |
674 | |
675 | // Then go from start_x+1 towards the right side of the bitmap. |
676 | // We might already be inside a lower span |
677 | inside_lower_span = ( drawer->GetPixel(start_x,y+1) == old_color ) && sel->ContainsPoint(x,y+1); |
678 | inside_upper_span = ( drawer->GetPixel(start_x,y-1) == old_color ) && sel->ContainsPoint(x,y-1); |
679 | x = start_x + 1; |
680 | while (sel->ContainsPoint(x,y) && (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) { |
681 | drawer->SetPixel(x,y,new_color); |
682 | |
683 | if ( (inside_lower_span == FALSE0) && (drawer->GetPixel(x,y+1) == old_color) && sel->ContainsPoint(x,y+1)) { |
684 | stack.Push(BPoint(x,y+1)); |
685 | inside_lower_span = TRUE1; |
686 | } |
687 | else if ( (inside_lower_span == TRUE1) && ((drawer->GetPixel(x,y+1) != old_color) || !sel->ContainsPoint(x,y+1)) ) { |
688 | inside_lower_span = FALSE0; |
689 | } |
690 | |
691 | if ( (inside_upper_span == FALSE0) && (drawer->GetPixel(x,y-1) == old_color) && sel->ContainsPoint(x,y-1)) { |
692 | stack.Push(BPoint(x,y-1)); |
693 | inside_upper_span = TRUE1; |
694 | } |
695 | else if ( (inside_upper_span == TRUE1) && ((drawer->GetPixel(x,y-1) != old_color) || !sel->ContainsPoint(x,y-1)) ) { |
696 | inside_upper_span = FALSE0; |
697 | } |
698 | |
699 | x++; |
700 | } |
701 | } |
702 | else { |
703 | // This is the case that takes the variance into account. We must use a |
704 | // binary bitmap to see what parts have already been filled. |
705 | uint32 binary_bpr = binary_fill_map->BytesPerRow(); |
706 | uchar *binary_bits = (uchar*)binary_fill_map->Bits(); |
707 | |
708 | // Then go from start towards the left side of the bitmap. |
709 | while (sel->ContainsPoint(x,y) && (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y), old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) { |
710 | drawer->SetPixel(x,y,new_color); |
711 | *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8)); |
712 | |
713 | if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) && sel->ContainsPoint(x,y+1) ) { |
714 | stack.Push(BPoint(x,y+1)); |
715 | inside_lower_span = TRUE1; |
716 | } |
717 | else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance) || !sel->ContainsPoint(x,y+1)) ) { |
718 | inside_lower_span = FALSE0; |
719 | } |
720 | |
721 | if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance)) && sel->ContainsPoint(x,y-1) ) { |
722 | stack.Push(BPoint(x,y-1)); |
723 | inside_upper_span = TRUE1; |
724 | } |
725 | else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1), old_color,tolerance) || !sel->ContainsPoint(x,y-1)) ) { |
726 | inside_upper_span = FALSE0; |
727 | } |
728 | |
729 | x--; |
730 | } |
731 | |
732 | // Then go from start_x+1 towards the right side of the bitmap. |
733 | // We might already be inside a lower span |
734 | inside_lower_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y+1),old_color,tolerance) && sel->ContainsPoint(start_x,y+1)); |
735 | inside_upper_span = ( compare_2_pixels_with_variance(drawer->GetPixel(start_x,y-1),old_color,tolerance) && sel->ContainsPoint(start_x,y-1)); |
736 | x = start_x + 1; |
737 | while (sel->ContainsPoint(x,y) && (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) && ((*(binary_bits + y*binary_bpr + (x/8))&(0x01 << (7-x%8))) == 0x00) ) { |
738 | drawer->SetPixel(x,y,new_color); |
739 | *(binary_bits + y*binary_bpr + (x/8)) |= (0x01 << (7 - x%8)); |
740 | |
741 | if ( (inside_lower_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance)) && sel->ContainsPoint(x,y+1) ) { |
742 | stack.Push(BPoint(x,y+1)); |
743 | inside_lower_span = TRUE1; |
744 | } |
745 | else if ( (inside_lower_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y+1),old_color,tolerance) || !sel->ContainsPoint(x,y+1)) ) { |
746 | inside_lower_span = FALSE0; |
747 | } |
748 | |
749 | if ( (inside_upper_span == FALSE0) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y-1), old_color,tolerance)) && sel->ContainsPoint(x,y-1) ) { |
750 | stack.Push(BPoint(x,y-1)); |
751 | inside_upper_span = TRUE1; |
752 | } |
753 | else if ( (inside_upper_span == TRUE1) && (!compare_2_pixels_with_variance(drawer->GetPixel(x,y-1),old_color,tolerance) || !sel->ContainsPoint(x,y-1)) ) { |
754 | inside_upper_span = FALSE0; |
755 | } |
756 | |
757 | x++; |
758 | } |
759 | } |
760 | } |
761 | } |
762 | |
763 | |
764 | void |
765 | FillTool::FillSpan(BPoint span_start,BitmapDrawer *drawer,int32 min_x, int32 max_x, uint32 new_color, uint32 old_color,int32 tolerance,Selection *sel) |
766 | { |
767 | // First get the vital data. |
768 | int32 x,start_x; |
769 | int32 y = (int32)span_start.y; |
770 | x = start_x = (int32)span_start.x; |
771 | |
772 | if ((sel == NULL__null) || (sel->IsEmpty() == TRUE1)) { |
773 | if ((tolerance == 0) && (binary_fill_map == NULL__null)) { |
774 | // Then go from start towards the left side of the bitmap. |
775 | while ( (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) { |
776 | drawer->SetPixel(x,y,new_color); |
777 | x--; |
778 | } |
779 | |
780 | // Then go from start_x+1 towards the right side of the bitmap. |
781 | x = start_x + 1; |
782 | while ( (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) { |
783 | drawer->SetPixel(x,y,new_color); |
784 | x++; |
785 | } |
786 | } |
787 | else { |
788 | // This is the case that takes the variance into account. We must use a |
789 | // binary bitmap to see what parts have already been filled. |
790 | uint32 binary_bpr = binary_fill_map->BytesPerRow(); |
791 | uchar *binary_bits = (uchar*)binary_fill_map->Bits(); |
792 | |
793 | // Then go from start towards the left side of the bitmap. |
794 | while ( (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y), old_color,tolerance)) ) { |
795 | drawer->SetPixel(x,y,new_color); |
796 | *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8)); |
797 | x--; |
798 | } |
799 | |
800 | // Then go from start_x+1 towards the right side of the bitmap. |
801 | x = start_x + 1; |
802 | while ( (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) ) { |
803 | drawer->SetPixel(x,y,new_color); |
804 | *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8)); |
805 | x++; |
806 | } |
807 | |
808 | } |
809 | } |
810 | else { |
811 | if ((tolerance == 0) && (binary_fill_map == NULL__null)) { |
812 | // Then go from start towards the left side of the bitmap. |
813 | while (sel->ContainsPoint(x,y) && (x >= min_x) && (drawer->GetPixel(x,y) == old_color) ) { |
814 | drawer->SetPixel(x,y,new_color); |
815 | x--; |
816 | } |
817 | |
818 | // Then go from start_x+1 towards the right side of the bitmap. |
819 | x = start_x + 1; |
820 | while (sel->ContainsPoint(x,y) && (x <= max_x) && (drawer->GetPixel(x,y) == old_color) ) { |
821 | drawer->SetPixel(x,y,new_color); |
822 | x++; |
823 | } |
824 | } |
825 | else { |
826 | // This is the case that takes the variance into account. We must use a |
827 | // binary bitmap to see what parts have already been filled. |
828 | uint32 binary_bpr = binary_fill_map->BytesPerRow(); |
829 | uchar *binary_bits = (uchar*)binary_fill_map->Bits(); |
830 | |
831 | // Then go from start towards the left side of the bitmap. |
832 | while (sel->ContainsPoint(x,y) && (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y), old_color,tolerance)) ) { |
833 | drawer->SetPixel(x,y,new_color); |
834 | *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8)); |
835 | x--; |
836 | } |
837 | |
838 | // Then go from start_x+1 towards the right side of the bitmap. |
839 | x = start_x + 1; |
840 | while (sel->ContainsPoint(x,y) && (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x,y),old_color,tolerance)) ) { |
841 | drawer->SetPixel(x,y,new_color); |
842 | *(binary_bits + y*binary_bpr + (x/8)) = *(binary_bits + y*binary_bpr + (x/8)) | (0x01 << (7 - x%8)); |
843 | x++; |
844 | } |
845 | |
846 | } |
847 | } |
848 | } |
849 | |
850 | |
851 | BPoint |
852 | FillTool::GradientFill(ImageView *view,uint32 buttons,BPoint start,BPoint orig_view_point,Selection *sel) |
853 | { |
854 | // First calculate points that are to be included in the fill to |
855 | // a separate binary mask. Then go through the filled areas bounds |
856 | // rectangle and fill only those pixels that the mask tells to. |
857 | // The color of pixel is to be calculated from the original mousedown point |
858 | // and the last mousedown point and from color values for mouse-button |
859 | // and gradien color. If preview is enabled we should also update in real time |
860 | // whenever possible. |
861 | |
862 | // Get the necessary parameters |
863 | // Wait for the last_updated_region to become empty |
864 | while (LastUpdatedRect().IsValid()) |
865 | snooze(50000); |
866 | |
867 | BWindow *window = view->Window(); |
868 | if (window == NULL__null) |
869 | return BPoint(-1,-1); |
870 | |
871 | BBitmap *bitmap = view->ReturnImage()->ReturnActiveBitmap(); |
872 | BitmapDrawer *drawer = new BitmapDrawer(bitmap); |
873 | BRect bitmap_bounds = bitmap->Bounds(); |
874 | bitmap_bounds.OffsetTo(BPoint(0,0)); |
875 | |
876 | window->Lock(); |
877 | drawing_mode old_mode = view->DrawingMode(); |
878 | view->SetDrawingMode(B_OP_INVERT); |
879 | window->Unlock(); |
880 | BPoint new_point = start; |
881 | |
882 | if (bitmap_bounds.Contains(start) == TRUE1) { |
883 | |
884 | // These are the edge coordinates of bitmap. It is still safe to |
885 | // address a pixel at max_x,max_y or min_x,min_y. |
886 | int32 min_x,min_y,max_x,max_y; |
887 | min_x = (int32)bitmap_bounds.left; |
888 | min_y = (int32)bitmap_bounds.top; |
889 | max_x = (int32)bitmap_bounds.right; |
890 | max_y = (int32)bitmap_bounds.bottom; |
891 | |
892 | // At this point we should take some action if min_x == max_x or min_y == max_y |
893 | |
894 | // Get the color for the fill. |
895 | // rgb_color c = ((PaintApplication*)be_app)->Color(buttons); |
896 | // uint32 color = RGBColorToBGRA(c); |
897 | |
898 | // // Get the gradient color. |
899 | // uint32 gradient_color = settings.gradient_color; |
900 | // Get the old color. |
901 | uint32 old_color = drawer->GetPixel(start); |
902 | |
903 | uint32 gradient_color = gradient_color1; |
904 | uint32 color = gradient_color2; |
905 | |
906 | // Here calculate the binary bitmap for the purpose of doing the gradient. |
907 | BBitmap *binary_map; |
908 | if (fToolSettings.mode == B_CONTROL_OFF) // Not flood-mode |
909 | binary_map = MakeBinaryMap(drawer,min_x,max_x,min_y,max_y,old_color,sel); |
910 | else // Flood-mode |
911 | binary_map = MakeFloodBinaryMap(drawer,min_x,max_x,min_y,max_y,old_color,start,sel); |
912 | |
913 | |
914 | // Here calculate the bounding rectangle of the filled area and |
915 | // change the min and max coordinates to those edges of the rect. |
916 | BRect filled_area_bounds = calcBinaryMapBounds(binary_map); |
917 | // min_x = filled_area_bounds.left; |
918 | // max_x = filled_area_bounds.right; |
919 | // min_y = filled_area_bounds.top; |
920 | // max_y = filled_area_bounds.bottom; |
921 | |
922 | BRect ellipse_rect = BRect(orig_view_point-BPoint(3,3),orig_view_point+BPoint(3,3)); |
923 | BPoint new_view_point = orig_view_point; |
924 | BPoint prev_view_point = new_view_point; |
925 | window->Lock(); |
926 | view->StrokeEllipse(ellipse_rect); |
927 | window->Unlock(); |
928 | if (fToolSettings.preview_enabled == B_CONTROL_OFF) { |
929 | // Do not do the preview. Just read the coordinates. |
930 | while (buttons) { |
931 | if (new_view_point != prev_view_point) { |
932 | window->Lock(); |
933 | view->StrokeEllipse(ellipse_rect); |
934 | window->Unlock(); |
935 | prev_view_point = new_view_point; |
936 | } |
937 | window->Lock(); |
938 | view->getCoords(&new_point,&buttons,&new_view_point); |
939 | window->Unlock(); |
940 | snooze(20 * 1000); |
941 | } |
942 | } |
943 | else { |
944 | // Display also preview of the gradient |
945 | while (buttons) { |
946 | if (new_view_point != prev_view_point) { |
947 | int32 dx = (int32)(start.x - new_point.x); |
948 | int32 dy = (int32)(start.y - new_point.y); |
949 | // There should actually be a separate function (and maybe even a thread) that calculates |
950 | // the preview in real time for some bitmap that is quite small (about 200x200 pixels maximum). |
951 | // Then the gradient would be copied to bitmap using some specialized function. |
952 | FillGradientPreview(drawer,binary_map,dx,dy,min_x,max_x,min_y,max_y,color,gradient_color); |
953 | view->ReturnImage()->RenderPreview(bitmap->Bounds(),2); |
954 | window->Lock(); |
955 | view->Draw(view->convertBitmapRectToView(filled_area_bounds)); |
956 | view->StrokeEllipse(ellipse_rect); |
957 | window->Unlock(); |
958 | prev_view_point = new_view_point; |
959 | } |
960 | window->Lock(); |
961 | view->getCoords(&new_point,&buttons,&new_view_point); |
962 | window->Unlock(); |
963 | snooze(20 * 1000); |
964 | } |
965 | } |
966 | // Here calculate the final gradient. |
967 | int32 dx = (int32)(start.x - new_point.x); |
968 | int32 dy = (int32)(start.y - new_point.y); |
969 | |
970 | FillGradient(drawer,binary_map,dx,dy,min_x,max_x,min_y,max_y,color,gradient_color); |
971 | |
972 | // Update the image-view. |
973 | view->ReturnImage()->Render(); |
974 | window->Lock(); |
975 | view->SetDrawingMode(old_mode); |
976 | view->Draw(view->convertBitmapRectToView(filled_area_bounds) | ellipse_rect); |
977 | window->Unlock(); |
978 | delete binary_map; |
979 | SetLastUpdatedRect(filled_area_bounds); |
980 | } |
981 | delete drawer; |
982 | return new_point; |
983 | } |
984 | |
985 | |
986 | |
987 | BBitmap* |
988 | FillTool::MakeBinaryMap(BitmapDrawer *drawer,int32 min_x,int32 max_x,int32 min_y,int32 max_y,uint32 old_color,Selection *sel) |
989 | { |
990 | // This function makes a binary bitmap that has ones where the |
991 | // color of original bitmap is same as old_color, and zeroes elsewhere. |
992 | BBitmap *binary_map = new BBitmap(BRect(min_x,min_y,max_x,max_y), B_GRAY1); |
993 | uchar *binary_bits = (uchar*)binary_map->Bits(); |
994 | int32 binary_bpr = binary_map->BytesPerRow(); |
995 | |
996 | if ((sel == NULL__null) || (sel->IsEmpty() == TRUE1)) { |
997 | if (fToolSettings.tolerance == 0) { |
998 | // Always collect eight pixels from the bitmap and then move that data to the binary bitmap. |
999 | uchar next_value = 0x00; |
1000 | for (int32 y=min_y;y<=max_y;y++) { |
1001 | int32 bytes_advanced = 0; |
1002 | for (int32 x=min_x;x<=max_x;x++) { |
1003 | if ( ((x % 8) == 0) && (x != 0) ) { |
1004 | *binary_bits++ = next_value; |
1005 | bytes_advanced++; |
1006 | next_value = 0x00; |
1007 | } |
1008 | next_value |= ( (old_color == drawer->GetPixel(x,y)) ? ( 0x01 << (7 - (x%8) )) : 0x00 ); |
1009 | } |
1010 | if ((max_x % 8) != 0) { |
1011 | *binary_bits++ = next_value; |
1012 | bytes_advanced++; |
1013 | next_value = 0x00; |
1014 | } |
1015 | binary_bits += binary_bpr - bytes_advanced; |
1016 | } |
1017 | } |
1018 | else { |
1019 | // Always collect eight pixels from the bitmap and then move that data to the binary bitmap. |
1020 | uchar next_value = 0x00; |
1021 | uint32 tolerance = (uint32)((float)fToolSettings.tolerance/100.0 * 255); |
1022 | for (int32 y=min_y;y<=max_y;y++) { |
1023 | int32 bytes_advanced = 0; |
1024 | for (int32 x=min_x;x<=max_x;x++) { |
1025 | if ( ((x % 8) == 0) && (x != 0) ) { |
1026 | *binary_bits++ = next_value; |
1027 | bytes_advanced++; |
1028 | next_value = 0x00; |
1029 | } |
1030 | next_value |= ( (compare_2_pixels_with_variance(old_color,drawer->GetPixel(x,y),tolerance)) ? ( 0x01 << (7 - (x%8) )) : 0x00 ); |
1031 | } |
1032 | if ((max_x % 8) != 0) { |
1033 | *binary_bits++ = next_value; |
1034 | bytes_advanced++; |
1035 | next_value = 0x00; |
1036 | } |
1037 | binary_bits += binary_bpr - bytes_advanced; |
1038 | } |
1039 | } |
1040 | } |
1041 | else { |
1042 | if (fToolSettings.tolerance == 0) { |
1043 | // Always collect eight pixels from the bitmap and then move that data to the binary bitmap. |
1044 | uchar next_value = 0x00; |
1045 | for (int32 y=min_y;y<=max_y;y++) { |
1046 | int32 bytes_advanced = 0; |
1047 | for (int32 x=min_x;x<=max_x;x++) { |
1048 | if ( ((x % 8) == 0) && (x != 0) ) { |
1049 | *binary_bits++ = next_value; |
1050 | bytes_advanced++; |
1051 | next_value = 0x00; |
1052 | } |
1053 | next_value |= ( ((old_color == drawer->GetPixel(x,y)) && sel->ContainsPoint(x,y)) ? ( 0x01 << (7 - (x%8) )) : 0x00 ); |
1054 | } |
1055 | if ((max_x % 8) != 0) { |
1056 | *binary_bits++ = next_value; |
1057 | bytes_advanced++; |
1058 | next_value = 0x00; |
1059 | } |
1060 | binary_bits += binary_bpr - bytes_advanced; |
1061 | } |
1062 | } |
1063 | else { |
1064 | // Always collect eight pixels from the bitmap and then move that data to the binary bitmap. |
1065 | uchar next_value = 0x00; |
1066 | uint32 tolerance = (uint32)((float)fToolSettings.tolerance/100.0 * 255); |
1067 | for (int32 y=min_y;y<=max_y;y++) { |
1068 | int32 bytes_advanced = 0; |
1069 | for (int32 x=min_x;x<=max_x;x++) { |
1070 | if ( ((x % 8) == 0) && (x != 0) ) { |
1071 | *binary_bits++ = next_value; |
1072 | bytes_advanced++; |
1073 | next_value = 0x00; |
1074 | } |
1075 | next_value |= ( (compare_2_pixels_with_variance(old_color,drawer->GetPixel(x,y),tolerance) && sel->ContainsPoint(x,y)) ? ( 0x01 << (7 - (x%8) )) : 0x00 ); |
1076 | } |
1077 | if ((max_x % 8) != 0) { |
1078 | *binary_bits++ = next_value; |
1079 | bytes_advanced++; |
1080 | next_value = 0x00; |
1081 | } |
1082 | binary_bits += binary_bpr - bytes_advanced; |
1083 | } |
1084 | } |
1085 | } |
1086 | return binary_map; |
1087 | } |
1088 | |
1089 | BBitmap* |
1090 | FillTool::MakeFloodBinaryMap(BitmapDrawer *drawer, int32 min_x, |
1091 | int32 max_x, int32 min_y, int32 max_y, uint32 old_color, BPoint start, |
1092 | Selection *sel) |
1093 | { |
1094 | // This function makes a binary bitmap of the image. It contains ones where |
1095 | // the flood fill should fill and zeroes elsewhere. |
1096 | BBitmap *binary_map; |
1097 | binary_map = binary_fill_map = new BBitmap(BRect(min_x,min_y,max_x,max_y), |
1098 | B_GRAY1); |
1099 | uchar *binary_bits = (uchar*)binary_map->Bits(); |
1100 | int32 binary_bitslength = binary_map->BitsLength(); |
1101 | // Clear the binary map. |
1102 | for (int32 i=0;i<binary_bitslength;i++) |
1103 | *binary_bits++ = 0x00; |
1104 | |
1105 | binary_bits = (uchar*)binary_map->Bits(); |
1106 | |
1107 | // We can use the functions CheckLowerSpans, CheckUpperSpans and CheckBothSpans |
1108 | // to calculate the binary_fill_map and then return it. |
1109 | |
1110 | // Here we proceed just like in the case of a normal fill, except that we do not |
1111 | // show the intermediate fill to the user. |
1112 | |
1113 | // Here fill the area using drawer's SetPixel and GetPixel. |
1114 | // The algorithm uses 4-connected version of flood-fill. |
1115 | // The SetPixel and GetPixel functions are versions that |
1116 | // do not check bounds so we have to be careful not to exceed |
1117 | // bitmap's bounds. |
1118 | uint32 color = 0xFFFFFFFF; // This is the temporary color that will be used |
1119 | // to fill the bitmap. |
1120 | uint32 tolerance = (uint32)((float)fToolSettings.tolerance/100.0 * 255); |
1121 | |
1122 | PointStack stack; |
1123 | stack.Push(start); |
1124 | |
1125 | while (!stack.IsEmpty()) { |
1126 | BPoint span_start = stack.Pop(); |
1127 | if ( (span_start.y == min_y) && (min_y != max_y) ) { |
1128 | // Only check the spans below this line |
1129 | CheckLowerSpans(span_start,drawer, stack,min_x,max_x,color,old_color,tolerance,sel); |
1130 | } |
1131 | else if ( (span_start.y == max_y) && (min_y != max_y) ) { |
1132 | // Only check the spans above this line. |
1133 | CheckUpperSpans(span_start,drawer, stack,min_x,max_x,color,old_color,tolerance,sel); |
1134 | } |
1135 | else if (min_y != max_y) { |
1136 | // Check the spans above and below this line. |
1137 | CheckBothSpans(span_start,drawer, stack,min_x,max_x,color,old_color,tolerance,sel); |
1138 | } |
1139 | else { |
1140 | // The image is only one pixel high. Fill the only span. |
1141 | FillSpan(span_start,drawer,min_x,max_x,color,old_color,tolerance,sel); |
1142 | } |
1143 | } |
1144 | |
1145 | // Remember to NULL the attribute binary_fill_map |
1146 | binary_fill_map = NULL__null; |
1147 | return binary_map; |
1148 | } |
1149 | |
1150 | |
1151 | void |
1152 | FillTool::FillGradient(BitmapDrawer *drawer, BBitmap *binary_map, int32 dx, |
1153 | int32 dy, int32 min_x, int32 max_x, int32 min_y, int32 max_y, |
1154 | uint32 new_color, uint32 gradient_color) |
1155 | { |
1156 | uchar *binary_bits = (uchar*)binary_map->Bits(); |
1157 | int32 binary_bpr = binary_map->BytesPerRow(); |
1158 | |
1159 | uint32 x_source,x_target; |
1160 | uint32 y_source,y_target; |
1161 | |
1162 | if (dx < 0) |
1163 | x_target = gradient_color; |
1164 | else |
1165 | x_target = new_color; |
1166 | |
1167 | if (dy<0) { |
1168 | y_target = gradient_color; |
1169 | y_source = new_color; |
1170 | } else { |
1171 | y_target = new_color; |
1172 | y_source = gradient_color; |
1173 | } |
1174 | uint32 y_gradient; |
1175 | uint32 x_gradient; |
1176 | |
1177 | // These might also be negative |
1178 | int16 x_red_diff,x_green_diff,x_blue_diff,x_alpha_diff; |
1179 | int16 y_red_diff,y_green_diff,y_blue_diff,y_alpha_diff; |
1180 | |
1181 | float x_accumulation; |
1182 | float y_accumulation = 0; |
1183 | |
1184 | y_gradient = y_source; |
Value stored to 'y_gradient' is never read | |
1185 | uchar next_value = 0; |
1186 | |
1187 | y_red_diff = (int16)((y_target>>8) & 0xFF) - (int16)((y_source>>8) & 0xFF); |
1188 | y_green_diff = (int16)((y_target>>16) & 0xFF) - (int16)((y_source>>16) & 0xFF); |
1189 | y_blue_diff = (int16)((y_target>>24) & 0xFF) - (int16)((y_source>>24) & 0xFF); |
1190 | y_alpha_diff = (int16)((y_target) & 0xFF) - (int16)((y_source) & 0xFF); |
1191 | |
1192 | |
1193 | for (int32 y = min_y; y <=max_y; ++y) { |
1194 | int32 bytes_advanced = 0; |
1195 | // Here we should move y-gradient 1 step closer to y-target |
1196 | // and put x-source to y-gradient. We should also recalculate |
1197 | // the x-gradient step. |
1198 | if (dy<0) { |
1199 | y_accumulation = (float)(abs(dy))/50.0*(float)(max_y-y)/(float)(max_y - min_y); |
1200 | if (y_accumulation < 1.0) { |
1201 | y_gradient = y_source |
1202 | + (((int32)(y_blue_diff * (1.0-y_accumulation))) << 24) |
1203 | + (((int32)(y_green_diff * (1.0-y_accumulation))) << 16) |
1204 | + (((int32)(y_red_diff * (1.0-y_accumulation))) << 8) |
1205 | + (((int32)(y_alpha_diff * (1.0-y_accumulation)))); |
1206 | } else { |
1207 | y_gradient = y_source; |
1208 | } |
1209 | } else { |
1210 | y_accumulation = (float)dy/50.0*(float)y/(float)(max_y - min_y); |
1211 | if (y_accumulation < 1.0) { |
1212 | y_gradient = y_source |
1213 | + (((int32)(y_blue_diff * y_accumulation)) << 24) |
1214 | + (((int32)(y_green_diff * y_accumulation)) << 16) |
1215 | + (((int32)(y_red_diff * y_accumulation)) << 8) |
1216 | + (((int32)(y_alpha_diff * y_accumulation))); |
1217 | } else { |
1218 | y_gradient = y_target; |
1219 | } |
1220 | } |
1221 | |
1222 | if (dx < 0) { |
1223 | x_source = new_color; |
1224 | x_target = y_gradient; |
1225 | } else { |
1226 | x_source = y_gradient; |
1227 | x_target = new_color; |
1228 | } |
1229 | |
1230 | x_red_diff = (int16)((x_target>>8) & 0xFF) - (int16)((x_source>>8) & 0xFF); |
1231 | x_green_diff = (int16)((x_target>>16) & 0xFF) - (int16)((x_source>>16) & 0xFF); |
1232 | x_blue_diff = (int16)((x_target>>24) & 0xFF) - (int16)((x_source>>24) & 0xFF); |
1233 | x_alpha_diff = (int16)((x_target) & 0xFF) - (int16)((x_source) & 0xFF); |
1234 | |
1235 | x_accumulation = 0; |
1236 | for (int32 x=min_x;x<=max_x;x++) { |
1237 | // This might crash if max_x == min_x |
1238 | if (dx < 0) |
1239 | x_accumulation = (float)abs(dx)/50.0*(float)(max_x-x)/(float)(max_x - min_x); |
1240 | else |
1241 | x_accumulation = (float)dx/50.0*(float)x/(float)(max_x - min_x); |
1242 | |
1243 | if ( (x % 8) == 0 ) { |
1244 | next_value = *binary_bits++; |
1245 | bytes_advanced++; |
1246 | } |
1247 | if ( next_value & (0x01 << (7-(x%8))) ) { |
1248 | // Here we should put a new value into position x,y |
1249 | if (dx<0) { |
1250 | if (x_accumulation < 1.0) { |
1251 | x_gradient = x_source |
1252 | + (((int32)(x_blue_diff * (1.0-x_accumulation))) << 24) |
1253 | + (((int32)(x_green_diff * (1.0-x_accumulation))) << 16) |
1254 | + (((int32)(x_red_diff * (1.0-x_accumulation))) << 8) |
1255 | + (((int32)(x_alpha_diff * (1.0-x_accumulation)))); |
1256 | drawer->SetPixel(x,y,x_gradient); |
1257 | } else { |
1258 | drawer->SetPixel(x, y, x_source); |
1259 | } |
1260 | } else { |
1261 | if (x_accumulation < 1.0) { |
1262 | x_gradient = x_source |
1263 | + (((int32)(x_blue_diff * x_accumulation)) << 24) |
1264 | + (((int32)(x_green_diff * x_accumulation)) << 16) |
1265 | + (((int32)(x_red_diff * x_accumulation)) << 8) |
1266 | + (((int32)(x_alpha_diff * x_accumulation))); |
1267 | drawer->SetPixel(x,y,x_gradient); |
1268 | } else { |
1269 | drawer->SetPixel(x,y,x_target); |
1270 | } |
1271 | } |
1272 | } |
1273 | } |
1274 | binary_bits += binary_bpr - bytes_advanced; |
1275 | } |
1276 | } |
1277 | |
1278 | |
1279 | void |
1280 | FillTool::FillGradientPreview(BitmapDrawer *drawer, BBitmap *binary_map, |
1281 | int32 dx, int32 dy, int32 min_x, int32 max_x, int32 min_y, int32 max_y, |
1282 | uint32 new_color, uint32 gradient_color) |
1283 | { |
1284 | // This preview fill calculates only every other pixel. |
1285 | uchar *binary_bits = (uchar*)binary_map->Bits(); |
1286 | int32 binary_bpr = binary_map->BytesPerRow(); |
1287 | |
1288 | uint32 x_source,x_target; |
1289 | uint32 y_source,y_target; |
1290 | |
1291 | |
1292 | if (dx<0) |
1293 | x_target = gradient_color; |
1294 | else |
1295 | x_target = new_color; |
1296 | |
1297 | if (dy<0) { |
1298 | y_target = gradient_color; |
1299 | y_source = new_color; |
1300 | } else { |
1301 | y_target = new_color; |
1302 | y_source = gradient_color; |
1303 | } |
1304 | uint32 y_gradient; |
1305 | uint32 x_gradient; |
1306 | |
1307 | // These might also be negative |
1308 | int16 x_red_diff,x_green_diff,x_blue_diff,x_alpha_diff; |
1309 | int16 y_red_diff,y_green_diff,y_blue_diff,y_alpha_diff; |
1310 | |
1311 | float x_accumulation; |
1312 | float y_accumulation = 0; |
1313 | |
1314 | y_gradient = y_source; |
1315 | uchar next_value = 0; |
1316 | uchar next_rows_value = 0; |
1317 | |
1318 | y_red_diff = (int16)((y_target>>8) & 0xFF) - (int16)((y_source>>8) & 0xFF); |
1319 | y_green_diff = (int16)((y_target>>16) & 0xFF) - (int16)((y_source>>16) & 0xFF); |
1320 | y_blue_diff = (int16)((y_target>>24) & 0xFF) - (int16)((y_source>>24) & 0xFF); |
1321 | y_alpha_diff = (int16)((y_target) & 0xFF) - (int16)((y_source) & 0xFF); |
1322 | |
1323 | for (int32 y = min_y; y <= max_y - 1; y+=2) { |
1324 | int32 bytes_advanced = 0; |
1325 | // Here we should move y-gradient 1 step closer to y-target |
1326 | // and put x-source to y-gradient. We should also recalculate |
1327 | // the x-gradient step. |
1328 | if (dy<0) { |
1329 | y_accumulation = (float)(abs(dy))/50.0*(float)(max_y-y)/(float)(max_y - min_y); |
1330 | if (y_accumulation < 1.0) { |
1331 | y_gradient = y_source |
1332 | + (((int32)(y_blue_diff * (1.0-y_accumulation))) << 24) |
1333 | + (((int32)(y_green_diff * (1.0-y_accumulation))) << 16) |
1334 | + (((int32)(y_red_diff * (1.0-y_accumulation))) << 8) |
1335 | + (((int32)(y_alpha_diff * (1.0-y_accumulation)))); |
1336 | } else { |
1337 | y_gradient = y_source; |
1338 | } |
1339 | } else { |
1340 | y_accumulation = (float)dy/50.0*(float)y/(float)(max_y - min_y); |
1341 | if (y_accumulation < 1.0) { |
1342 | y_gradient = y_source |
1343 | + (((int32)(y_blue_diff * y_accumulation)) << 24) |
1344 | + (((int32)(y_green_diff * y_accumulation)) << 16) |
1345 | + (((int32)(y_red_diff * y_accumulation)) << 8) |
1346 | + (((int32)(y_alpha_diff * y_accumulation))); |
1347 | } else { |
1348 | y_gradient = y_target; |
1349 | } |
1350 | } |
1351 | |
1352 | if (dx<0) { |
1353 | x_source = new_color; |
1354 | x_target = y_gradient; |
1355 | } else { |
1356 | x_source = y_gradient; |
1357 | x_target = new_color; |
1358 | } |
1359 | |
1360 | x_red_diff = (int16)((x_target>>8) & 0xFF) - (int16)((x_source>>8) & 0xFF); |
1361 | x_green_diff = (int16)((x_target>>16) & 0xFF) - (int16)((x_source>>16) & 0xFF); |
1362 | x_blue_diff = (int16)((x_target>>24) & 0xFF) - (int16)((x_source>>24) & 0xFF); |
1363 | x_alpha_diff = (int16)((x_target) & 0xFF) - (int16)((x_source) & 0xFF); |
1364 | |
1365 | x_accumulation = 0; |
1366 | for (int32 x=min_x;x<=max_x-1;x+=2) { |
1367 | // This might crash if max_x == min_x |
1368 | if (dx < 0) |
1369 | x_accumulation = (float)abs(dx)/50.0*(float)(max_x-x)/(float)(max_x - min_x); |
1370 | else |
1371 | x_accumulation = (float)dx/50.0*(float)x/(float)(max_x - min_x); |
1372 | |
1373 | if ( (x % 8) == 0 ) { |
1374 | next_rows_value = *(binary_bits+binary_bpr); |
1375 | next_value = *binary_bits++; |
1376 | bytes_advanced++; |
1377 | } |
1378 | if ( next_value & (0x01 << (7-(x%8))) ) { |
1379 | // Here we should put a new value into position x,y |
1380 | if (dx < 0) { |
1381 | if (x_accumulation < 1.0) { |
1382 | x_gradient = x_source |
1383 | + (((int32)(x_blue_diff * (1.0-x_accumulation))) << 24) |
1384 | + (((int32)(x_green_diff * (1.0-x_accumulation))) << 16) |
1385 | + (((int32)(x_red_diff * (1.0-x_accumulation))) << 8) |
1386 | + (((int32)(x_alpha_diff * (1.0-x_accumulation)))); |
1387 | drawer->SetPixel(x,y,x_gradient); |
1388 | |
1389 | if (next_value & (0x01 << (7-((x+1)%8)))) |
1390 | drawer->SetPixel(x+1,y,x_gradient); |
1391 | |
1392 | if (next_rows_value & (0x01 << (7-(x%8)))) |
1393 | drawer->SetPixel(x,y+1,x_gradient); |
1394 | |
1395 | if (next_rows_value & (0x01 << (7-((x+1)%8)))) |
1396 | drawer->SetPixel(x+1,y+1,x_gradient); |
1397 | } else { |
1398 | drawer->SetPixel(x,y,x_source); |
1399 | if (next_value & (0x01 << (7-((x+1)%8)))) |
1400 | drawer->SetPixel(x+1,y,x_source); |
1401 | |
1402 | if (next_rows_value & (0x01 << (7-(x%8)))) |
1403 | drawer->SetPixel(x,y+1,x_source); |
1404 | |
1405 | if (next_rows_value & (0x01 << (7-((x+1)%8)))) |
1406 | drawer->SetPixel(x+1,y+1,x_source); |
1407 | } |
1408 | } else { |
1409 | if (x_accumulation < 1.0) { |
1410 | x_gradient = x_source |
1411 | + (((int32)(x_blue_diff * x_accumulation)) << 24) |
1412 | + (((int32)(x_green_diff * x_accumulation)) << 16) |
1413 | + (((int32)(x_red_diff * x_accumulation)) << 8) |
1414 | + (((int32)(x_alpha_diff * x_accumulation))); |
1415 | drawer->SetPixel(x,y,x_gradient); |
1416 | |
1417 | if (next_value & (0x01 << (7-((x+1)%8)))) |
1418 | drawer->SetPixel(x+1,y,x_gradient); |
1419 | |
1420 | if (next_rows_value & (0x01 << (7-(x%8)))) |
1421 | drawer->SetPixel(x,y+1,x_gradient); |
1422 | |
1423 | if (next_rows_value & (0x01 << (7-((x+1)%8)))) |
1424 | drawer->SetPixel(x+1,y+1,x_gradient); |
1425 | } else { |
1426 | drawer->SetPixel(x,y,x_target); |
1427 | if (next_value & (0x01 << (7-((x+1)%8)))) |
1428 | drawer->SetPixel(x+1,y,x_target); |
1429 | |
1430 | if (next_rows_value & (0x01 << (7-(x%8)))) |
1431 | drawer->SetPixel(x,y+1,x_target); |
1432 | |
1433 | if (next_rows_value & (0x01 << (7-((x+1)%8)))) |
1434 | drawer->SetPixel(x+1,y+1,x_target); |
1435 | } |
1436 | } |
1437 | } |
1438 | } |
1439 | binary_bits += binary_bpr - bytes_advanced+binary_bpr; |
1440 | } |
1441 | } |
1442 | |
1443 | |
1444 | BRect |
1445 | FillTool::calcBinaryMapBounds(BBitmap *boolean_map) |
1446 | { |
1447 | // it seems like the monochrome-bitmap is aligned at 16-bit boundary instead |
1448 | // of 32-bit as the BeBook claims |
1449 | char *bits = (char*)boolean_map->Bits(); |
1450 | int32 bpr = boolean_map->BytesPerRow(); |
1451 | bool selected_line; |
1452 | |
1453 | // this is an invalid rect |
1454 | BRect rc = BRect(100000,100000,-100000,-100000); |
1455 | |
1456 | int32 height = boolean_map->Bounds().IntegerHeight(); |
1457 | for (int32 y=0;y<=height;y++) { |
1458 | selected_line = FALSE0; |
1459 | for (int32 i=0;i<bpr;i++) { |
1460 | selected_line |= *bits != 0x00; |
1461 | if (*bits != 0x00) { |
1462 | for (int32 b=0;b<8;b++) { |
1463 | rc.left = min_c(rc.left,i*8+(((*bits>>(7-b))& 0x00000001) ? b : 100000))((rc.left)>(i*8+(((*bits>>(7-b))& 0x00000001) ? b : 100000))?(i*8+(((*bits>>(7-b))& 0x00000001) ? b : 100000)):(rc.left)); |
1464 | rc.right = max_c(rc.right,i*8+(((*bits>>(7-b))& 0x00000001) ? b : -100000))((rc.right)>(i*8+(((*bits>>(7-b))& 0x00000001) ? b : -100000))?(rc.right):(i*8+(((*bits>>(7-b))& 0x00000001 ) ? b : -100000))); |
1465 | } |
1466 | } |
1467 | ++bits; |
1468 | } |
1469 | if (selected_line) { |
1470 | rc.top = min_c(rc.top,y)((rc.top)>(y)?(y):(rc.top)); |
1471 | rc.bottom = max_c(rc.bottom,y)((rc.bottom)>(y)?(rc.bottom):(y)); |
1472 | } |
1473 | } |
1474 | |
1475 | return rc & boolean_map->Bounds(); |
1476 | } |
1477 | |
1478 | |
1479 | status_t |
1480 | FillTool::readSettings(BFile &file,bool is_little_endian) |
1481 | { |
1482 | if (DrawingTool::readSettings(file,is_little_endian) != B_OK((int)0)) |
1483 | return B_ERROR(-1); |
1484 | |
1485 | if (file.Read(&gradient_color1,sizeof(uint32)) != sizeof(uint32)) |
1486 | return B_ERROR(-1); |
1487 | |
1488 | if (file.Read(&gradient_color2,sizeof(uint32)) != sizeof(uint32)) |
1489 | return B_ERROR(-1); |
1490 | |
1491 | if (is_little_endian) { |
1492 | gradient_color1 = B_LENDIAN_TO_HOST_INT32(gradient_color1)(uint32)(gradient_color1); |
1493 | gradient_color2 = B_LENDIAN_TO_HOST_INT32(gradient_color2)(uint32)(gradient_color2); |
1494 | } else { |
1495 | gradient_color1 = B_BENDIAN_TO_HOST_INT32(gradient_color1)(uint32)__builtin_bswap32(gradient_color1); |
1496 | gradient_color2 = B_BENDIAN_TO_HOST_INT32(gradient_color2)(uint32)__builtin_bswap32(gradient_color2); |
1497 | } |
1498 | |
1499 | return B_OK((int)0); |
1500 | } |
1501 | |
1502 | |
1503 | status_t |
1504 | FillTool::writeSettings(BFile &file) |
1505 | { |
1506 | if (DrawingTool::writeSettings(file) != B_OK((int)0)) |
1507 | return B_ERROR(-1); |
1508 | |
1509 | if (file.Write(&gradient_color1,sizeof(uint32)) != sizeof(uint32)) |
1510 | return B_ERROR(-1); |
1511 | |
1512 | if (file.Write(&gradient_color2,sizeof(uint32)) != sizeof(uint32)) |
1513 | return B_ERROR(-1); |
1514 | |
1515 | return B_OK((int)0); |
1516 | |
1517 | } |
1518 | |
1519 | |
1520 | const void* |
1521 | FillTool::ToolCursor() const |
1522 | { |
1523 | return HS_FILL_CURSOR; |
1524 | } |
1525 | |
1526 | |
1527 | const char* |
1528 | FillTool::HelpString(bool isInUse) const |
1529 | { |
1530 | return (isInUse |
1531 | ? B_TRANSLATE("Making a fill.")BLocaleRoster::Default()->GetCatalog()->GetString(("Making a fill." ), "Tools") |
1532 | : B_TRANSLATE("Click to make a fill.")BLocaleRoster::Default()->GetCatalog()->GetString(("Click to make a fill." ), "Tools")); |
1533 | } |
1534 | |
1535 | |
1536 | // #pragma mark -- GradientView |
1537 | |
1538 | |
1539 | #define GRADIENT_ADJUSTED'gRad' 'gRad' |
1540 | |
1541 | |
1542 | class FillToolConfigView::GradientView : public BControl { |
1543 | public: |
1544 | GradientView(uint32,uint32); |
1545 | virtual ~GradientView(); |
1546 | |
1547 | virtual void AttachedToWindow(); |
1548 | virtual void Draw(BRect); |
1549 | virtual void MessageReceived(BMessage*); |
1550 | virtual void MouseDown(BPoint); |
1551 | virtual void FrameResized(float newWidth, float newHeight); |
1552 | virtual void LayoutChanged(); |
1553 | |
1554 | private: |
1555 | void _CalculateGradient(); |
1556 | |
1557 | private: |
1558 | rgb_color fColor1; |
1559 | rgb_color fColor2; |
1560 | |
1561 | BBitmap* fGradient; |
1562 | }; |
1563 | |
1564 | |
1565 | FillToolConfigView::GradientView::GradientView(uint32 c1, uint32 c2) |
1566 | : BControl("gradient view", "Gradient", new BMessage(GRADIENT_ADJUSTED'gRad'), |
1567 | B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS) |
1568 | , fGradient(NULL__null) |
1569 | { |
1570 | fColor1 = BGRAColorToRGB(c1); |
1571 | fColor2 = BGRAColorToRGB(c2); |
1572 | |
1573 | Message()->AddInt32("color1",RGBColorToBGRA(fColor1)); |
1574 | Message()->AddInt32("color2",RGBColorToBGRA(fColor2)); |
1575 | |
1576 | SetExplicitMinSize(BSize(100.0, 20.0)); |
1577 | SetExplicitMaxSize(BSize(B_SIZE_UNSET, 20.0)); |
1578 | } |
1579 | |
1580 | |
1581 | FillToolConfigView::GradientView::~GradientView() |
1582 | { |
1583 | delete fGradient; |
1584 | } |
1585 | |
1586 | |
1587 | void |
1588 | FillToolConfigView::GradientView::AttachedToWindow() |
1589 | { |
1590 | BControl::AttachedToWindow(); |
1591 | |
1592 | delete fGradient; |
1593 | |
1594 | BRect bounds = Bounds(); |
1595 | bounds.bottom = bounds.top; |
1596 | fGradient = new BBitmap(bounds, B_RGB32); |
1597 | |
1598 | _CalculateGradient(); |
1599 | } |
1600 | |
1601 | |
1602 | void |
1603 | FillToolConfigView::GradientView::LayoutChanged() |
1604 | { |
1605 | BControl::LayoutChanged(); |
1606 | |
1607 | delete fGradient; |
1608 | |
1609 | BRect bounds = Bounds(); |
1610 | bounds.bottom = bounds.top; |
1611 | fGradient = new BBitmap(bounds, B_RGB32); |
1612 | |
1613 | _CalculateGradient(); |
1614 | } |
1615 | |
1616 | |
1617 | void |
1618 | FillToolConfigView::GradientView::Draw(BRect rect) |
1619 | { |
1620 | BControl::Draw(rect); |
1621 | |
1622 | SetHighColor(0, 0, 0, 255); |
1623 | StrokeRect(Bounds()); |
1624 | |
1625 | BRect bounds = Bounds(); |
1626 | bounds.InsetBy(1.0, 1.0); |
1627 | DrawBitmap(fGradient, fGradient->Bounds(), bounds); |
1628 | } |
1629 | |
1630 | |
1631 | void |
1632 | FillToolConfigView::GradientView::MessageReceived(BMessage* message) |
1633 | { |
1634 | switch (message->what) { |
1635 | case B_PASTE: { |
1636 | if (message->WasDropped()) { |
1637 | BPoint dropPoint = ConvertFromScreen(message->DropPoint()); |
1638 | |
1639 | ssize_t size; |
1640 | const void* data; |
1641 | if (message->FindData("RGBColor", B_RGB_COLOR_TYPE, &data, |
1642 | &size) == B_OK((int)0) && size == sizeof(rgb_color)) { |
1643 | if (dropPoint.x < (Bounds().right / 2.0)) |
1644 | memcpy((void*)(&fColor1), data, size); |
1645 | else |
1646 | memcpy((void*)(&fColor2), data, size); |
1647 | |
1648 | Message()->ReplaceInt32("color1", RGBColorToBGRA(fColor1)); |
1649 | Message()->ReplaceInt32("color2", RGBColorToBGRA(fColor2)); |
1650 | |
1651 | _CalculateGradient(); |
1652 | Draw(Bounds()); |
1653 | Invoke(); |
1654 | } |
1655 | } |
1656 | } break; |
1657 | |
1658 | default: { |
1659 | BControl::MessageReceived(message); |
1660 | } break; |
1661 | } |
1662 | } |
1663 | |
1664 | |
1665 | void |
1666 | FillToolConfigView::GradientView::MouseDown(BPoint point) |
1667 | { |
1668 | BControl::MouseDown(point); |
1669 | |
1670 | rgb_color color = fColor1; |
1671 | if (point.x > (Bounds().right / 2.0)) |
1672 | color = fColor2; |
1673 | |
1674 | // Open the palette-view. |
1675 | ColorPaletteWindow::showPaletteWindow(); |
1676 | ColorPaletteWindow::ChangePaletteColor(color); |
1677 | } |
1678 | |
1679 | |
1680 | void |
1681 | FillToolConfigView::GradientView::FrameResized(float newWidth, float newHeight) |
1682 | { |
1683 | delete fGradient; |
1684 | fGradient = new BBitmap(BRect(0, 0, newWidth, 0), B_RGB32); |
1685 | |
1686 | _CalculateGradient(); |
1687 | } |
1688 | |
1689 | |
1690 | void |
1691 | FillToolConfigView::GradientView::_CalculateGradient() |
1692 | { |
1693 | union { |
1694 | uint8 bytes[4]; |
1695 | uint32 word; |
1696 | } c; |
1697 | |
1698 | uint32 c1 = RGBColorToBGRA(fColor1); |
1699 | uint32 c2 = RGBColorToBGRA(fColor2); |
1700 | |
1701 | uint32 *bits = (uint32*)fGradient->Bits(); |
1702 | int32 width = fGradient->BytesPerRow() / 4; |
1703 | |
1704 | for (int32 x = 0; x < width; ++x) { |
1705 | uint32 fixed_alpha = (1.0 - float(x) / float(width + 1.0)) * 32768; |
1706 | c.word = mix_2_pixels_fixed(c1, c2, fixed_alpha); |
1707 | float coeff = c.bytes[3] / 255.0; |
1708 | if ((x % 2) == 0) { |
1709 | c.bytes[0] = (uint8)(c.bytes[0] * coeff); |
1710 | c.bytes[1] = (uint8)(c.bytes[1] * coeff); |
1711 | c.bytes[2] = (uint8)(c.bytes[2] * coeff); |
1712 | } else { |
1713 | c.bytes[0] = (uint8)(c.bytes[0] * coeff + (1 - coeff) * 255); |
1714 | c.bytes[1] = (uint8)(c.bytes[1] * coeff + (1 - coeff) * 255); |
1715 | c.bytes[2] = (uint8)(c.bytes[2] * coeff + (1 - coeff) * 255); |
1716 | } |
1717 | *bits++ = c.word; |
1718 | } |
1719 | } |
1720 | |
1721 | |
1722 | // #pragma mark -- FillToolConfigView |
1723 | |
1724 | |
1725 | FillToolConfigView::FillToolConfigView(DrawingTool* tool,uint32 c1, uint32 c2) |
1726 | : DrawingToolConfigView(tool) |
1727 | { |
1728 | if (BLayout* layout = GetLayout()) { |
1729 | BMessage* message = new BMessage(OPTION_CHANGED); |
1730 | message->AddInt32("option", MODE_OPTION); |
1731 | message->AddInt32("value", 0x00000000); |
1732 | fFlodFill = new BCheckBox(B_TRANSLATE("Flood fill")BLocaleRoster::Default()->GetCatalog()->GetString(("Flood fill" ), "Tools"), |
1733 | message); |
1734 | |
1735 | message = new BMessage(OPTION_CHANGED); |
1736 | message->AddInt32("option", GRADIENT_ENABLED_OPTION); |
1737 | message->AddInt32("value", 0x00000000); |
1738 | fGradient = |
1739 | new BCheckBox(B_TRANSLATE("Enable gradient")BLocaleRoster::Default()->GetCatalog()->GetString(("Enable gradient" ), "Tools"), |
1740 | message); |
1741 | |
1742 | message = new BMessage(OPTION_CHANGED); |
1743 | message->AddInt32("option", PREVIEW_ENABLED_OPTION); |
1744 | message->AddInt32("value", 0x00000000); |
1745 | fPreview = new BCheckBox(B_TRANSLATE("Enable preview")BLocaleRoster::Default()->GetCatalog()->GetString(("Enable preview" ), "Tools"), |
1746 | message); |
1747 | |
1748 | fGradientView = new GradientView(c1, c2); |
1749 | |
1750 | message = new BMessage(OPTION_CHANGED); |
1751 | message->AddInt32("option",TOLERANCE_OPTION); |
1752 | message->AddInt32("value",tool->GetCurrentValue(TOLERANCE_OPTION)); |
1753 | fTolerance = |
1754 | new NumberSliderControl(B_TRANSLATE("Tolerance:")BLocaleRoster::Default()->GetCatalog()->GetString(("Tolerance:" ), "Tools"), |
1755 | "0", message, 0, 100, false); |
1756 | fTolerance->SetValue(tool->GetCurrentValue(TOLERANCE_OPTION)); |
1757 | |
1758 | BGridLayout* toleranceLayout = LayoutSliderGrid(fTolerance); |
1759 | |
1760 | layout->AddView(BGroupLayoutBuilder(B_VERTICAL, kWidgetSpacing) |
1761 | .Add(toleranceLayout) |
1762 | .AddStrut(kWidgetSpacing) |
1763 | .Add(SeparatorView(B_TRANSLATE("Mode")BLocaleRoster::Default()->GetCatalog()->GetString(("Mode" ), "Tools"))) |
1764 | .AddGroup(B_VERTICAL, kWidgetSpacing) |
1765 | .Add(fFlodFill) |
1766 | .SetInsets(kWidgetInset, 0.0, 0.0, 0.0) |
1767 | .End() |
1768 | .AddStrut(kWidgetSpacing) |
1769 | .Add(SeparatorView(B_TRANSLATE("Options")BLocaleRoster::Default()->GetCatalog()->GetString(("Options" ), "Tools"))) |
1770 | .AddGroup(B_VERTICAL, kWidgetSpacing) |
1771 | .Add(fGradient) |
1772 | .Add(fPreview) |
1773 | .Add(fGradientView) |
1774 | .SetInsets(kWidgetInset, 0.0, 0.0, 0.0) |
1775 | .End() |
1776 | .TopView() |
1777 | ); |
1778 | |
1779 | fFlodFill->SetValue(tool->GetCurrentValue(MODE_OPTION)); |
1780 | |
1781 | if (tool->GetCurrentValue(GRADIENT_ENABLED_OPTION) != B_CONTROL_OFF) |
1782 | fGradient->SetValue(B_CONTROL_ON); |
1783 | |
1784 | if (tool->GetCurrentValue(PREVIEW_ENABLED_OPTION) != B_CONTROL_OFF) |
1785 | fPreview->SetValue(B_CONTROL_ON); |
1786 | } |
1787 | } |
1788 | |
1789 | |
1790 | void |
1791 | FillToolConfigView::AttachedToWindow() |
1792 | { |
1793 | DrawingToolConfigView::AttachedToWindow(); |
1794 | |
1795 | fFlodFill->SetTarget(this); |
1796 | fGradient->SetTarget(this); |
1797 | fPreview->SetTarget(this); |
1798 | fGradientView->SetTarget(this); |
1799 | fTolerance->SetTarget(this); |
1800 | } |
1801 | |
1802 | |
1803 | void |
1804 | FillToolConfigView::MessageReceived(BMessage *message) |
1805 | { |
1806 | switch (message->what) { |
1807 | case GRADIENT_ADJUSTED'gRad': { |
1808 | uint32 color1; |
1809 | uint32 color2; |
1810 | message->FindInt32("color1", (int32*)&color1); |
1811 | message->FindInt32("color2", (int32*)&color2); |
1812 | (dynamic_cast<FillTool*> (Tool()))->SetGradient(color1, color2); |
1813 | } break; |
1814 | |
1815 | default: { |
1816 | DrawingToolConfigView::MessageReceived(message); |
1817 | } break; |
1818 | } |
1819 | } |
1820 |