File: | home/HaikuArchives/ArtPaint/artpaint/tools/BrushTool.cpp |
Warning: | line 86, column 10 Potential leak of memory pointed to by 'coordinate_reader' |
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 "BrushTool.h" | |||
14 | ||||
15 | #include "BitmapUtilities.h" | |||
16 | #include "Brush.h" | |||
17 | #include "BrushEditor.h" | |||
18 | #include "CoordinateReader.h" | |||
19 | #include "CoordinateQueue.h" | |||
20 | #include "Cursors.h" | |||
21 | #include "Image.h" | |||
22 | #include "ImageUpdater.h" | |||
23 | #include "ImageView.h" | |||
24 | #include "PaintApplication.h" | |||
25 | #include "PixelOperations.h" | |||
26 | #include "Selection.h" | |||
27 | #include "ToolScript.h" | |||
28 | #include "UtilityClasses.h" | |||
29 | ||||
30 | ||||
31 | #include <Catalog.h> | |||
32 | #include <File.h> | |||
33 | #include <Layout.h> | |||
34 | #include <Window.h> | |||
35 | ||||
36 | ||||
37 | #undef B_TRANSLATION_CONTEXT"Tools" | |||
38 | #define B_TRANSLATION_CONTEXT"Tools" "Tools" | |||
39 | ||||
40 | ||||
41 | BrushTool::BrushTool() | |||
42 | : DrawingTool(B_TRANSLATE("Brush tool")BLocaleRoster::Default()->GetCatalog()->GetString(("Brush tool" ), "Tools"), BRUSH_TOOL) | |||
43 | { | |||
44 | // Options will also have some brush-data options. | |||
45 | fOptions = 0; | |||
46 | fOptionsCount = 0; | |||
47 | ||||
48 | brush_info info; | |||
49 | info.shape = HS_ELLIPTICAL_BRUSH; | |||
50 | info.width = 30; | |||
51 | info.height = 30; | |||
52 | info.angle = 0; | |||
53 | info.hardness = 2; | |||
54 | ||||
55 | brush = new Brush(info); | |||
56 | } | |||
57 | ||||
58 | ||||
59 | BrushTool::~BrushTool() | |||
60 | { | |||
61 | delete brush; | |||
62 | } | |||
63 | ||||
64 | ||||
65 | ToolScript* | |||
66 | BrushTool::UseTool(ImageView *view, uint32 buttons, BPoint point, BPoint viewPoint) | |||
67 | { | |||
68 | B_UNUSED(buttons)(void)buttons; | |||
69 | B_UNUSED(viewPoint)(void)viewPoint; | |||
70 | ||||
71 | // Wait for the last_updated_region to become empty | |||
72 | while (LastUpdatedRect().IsValid()) | |||
| ||||
73 | snooze(50000); | |||
74 | ||||
75 | CoordinateReader* coordinate_reader = new CoordinateReader(view, | |||
76 | LINEAR_INTERPOLATION, false); | |||
77 | ||||
78 | ToolScript* the_script = new ToolScript(Type(), fToolSettings, | |||
79 | ((PaintApplication*)be_app)->Color(true)); | |||
80 | ||||
81 | selection = view->GetSelection(); | |||
82 | ||||
83 | BBitmap* buffer = view->ReturnImage()->ReturnActiveBitmap(); | |||
84 | BBitmap* srcBuffer = new (std::nothrow) BBitmap(buffer); | |||
85 | if (srcBuffer == NULL__null) | |||
86 | return NULL__null; | |||
| ||||
87 | ||||
88 | bits = (uint32*)buffer->Bits(); | |||
89 | bpr = buffer->BytesPerRow()/4; | |||
90 | BRect bitmap_bounds = buffer->Bounds(); | |||
91 | ||||
92 | left_bound = (int32)bitmap_bounds.left; | |||
93 | right_bound = (int32)bitmap_bounds.right; | |||
94 | top_bound = (int32)bitmap_bounds.top; | |||
95 | bottom_bound = (int32)bitmap_bounds.bottom; | |||
96 | ||||
97 | BBitmap* tmpBuffer = new (std::nothrow) BBitmap(bitmap_bounds, | |||
98 | buffer->ColorSpace()); | |||
99 | if (tmpBuffer == NULL__null) { | |||
100 | delete srcBuffer; | |||
101 | return NULL__null; | |||
102 | } | |||
103 | ||||
104 | float brush_width_per_2 = floor(brush->Width()/2); | |||
105 | float brush_height_per_2 = floor(brush->Height()/2); | |||
106 | ||||
107 | BPoint prev_point; | |||
108 | ||||
109 | union color_conversion new_color; | |||
110 | ||||
111 | new_color.word = | |||
112 | RGBColorToBGRA(((PaintApplication*)be_app)->Color(true)); | |||
113 | ||||
114 | union color_conversion clear_color; | |||
115 | clear_color.word = new_color.word; | |||
116 | clear_color.bytes[3] = 0x01; | |||
117 | ||||
118 | BitmapUtilities::ClearBitmap(tmpBuffer, clear_color.word); | |||
119 | ||||
120 | prev_point = last_point = point; | |||
121 | BRect updated_rect; | |||
122 | ||||
123 | the_script->AddPoint(point); | |||
124 | ||||
125 | if (coordinate_reader->GetPoint(point) == B_OK((int)0)) { | |||
126 | draw_brush(tmpBuffer, BPoint(point.x - brush_width_per_2, | |||
127 | point.y - brush_height_per_2), 0, 0, new_color.word); | |||
128 | } | |||
129 | ||||
130 | updated_rect = BRect(point.x - brush_width_per_2, | |||
131 | point.y - brush_height_per_2, point.x + brush_width_per_2, | |||
132 | point.y + brush_height_per_2); | |||
133 | SetLastUpdatedRect(updated_rect); | |||
134 | buffer->Lock(); | |||
135 | BitmapUtilities::CompositeBitmapOnSource(buffer, srcBuffer, | |||
136 | tmpBuffer, updated_rect); | |||
137 | buffer->Unlock(); | |||
138 | prev_point = point; | |||
139 | ||||
140 | ImageUpdater* imageUpdater = new ImageUpdater(view, 20000); | |||
141 | imageUpdater->AddRect(updated_rect); | |||
142 | ||||
143 | while (coordinate_reader->GetPoint(point) == B_OK((int)0)) { | |||
144 | draw_brush(tmpBuffer, BPoint(point.x - brush_width_per_2, | |||
145 | point.y - brush_height_per_2), int32(point.x - prev_point.x), | |||
146 | int32(point.y - prev_point.y), new_color.word); | |||
147 | updated_rect = BRect(point.x - brush_width_per_2, | |||
148 | point.y - brush_height_per_2, point.x + brush_width_per_2, | |||
149 | point.y + brush_height_per_2); | |||
150 | imageUpdater->AddRect(updated_rect); | |||
151 | SetLastUpdatedRect(updated_rect | LastUpdatedRect()); | |||
152 | buffer->Lock(); | |||
153 | BitmapUtilities::CompositeBitmapOnSource(buffer, srcBuffer, | |||
154 | tmpBuffer, updated_rect); | |||
155 | buffer->Unlock(); | |||
156 | prev_point = point; | |||
157 | } | |||
158 | ||||
159 | imageUpdater->ForceUpdate(); | |||
160 | ||||
161 | delete imageUpdater; | |||
162 | delete coordinate_reader; | |||
163 | ||||
164 | // test_brush(point,new_color); | |||
165 | // if (view->LockLooper() == true) { | |||
166 | // view->UpdateImage(view->Bounds()); | |||
167 | // view->Invalidate(); | |||
168 | // view->UnlockLooper(); | |||
169 | // } | |||
170 | ||||
171 | delete srcBuffer; | |||
172 | delete tmpBuffer; | |||
173 | ||||
174 | return the_script; | |||
175 | } | |||
176 | ||||
177 | ||||
178 | int32 | |||
179 | BrushTool::UseToolWithScript(ToolScript*, BBitmap*) | |||
180 | { | |||
181 | return B_OK((int)0); | |||
182 | } | |||
183 | ||||
184 | ||||
185 | BView* | |||
186 | BrushTool::ConfigView() | |||
187 | { | |||
188 | return new BrushToolConfigView(this); | |||
189 | } | |||
190 | ||||
191 | ||||
192 | const void* | |||
193 | BrushTool::ToolCursor() const | |||
194 | { | |||
195 | return HS_BRUSH_CURSOR; | |||
196 | } | |||
197 | ||||
198 | ||||
199 | const char* | |||
200 | BrushTool::HelpString(bool isInUse) const | |||
201 | { | |||
202 | return (isInUse | |||
203 | ? B_TRANSLATE("Painting with a brush.")BLocaleRoster::Default()->GetCatalog()->GetString(("Painting with a brush." ), "Tools") | |||
204 | : B_TRANSLATE("Click to paint with a brush.")BLocaleRoster::Default()->GetCatalog()->GetString(("Click to paint with a brush." ), "Tools")); | |||
205 | } | |||
206 | ||||
207 | ||||
208 | BRect | |||
209 | BrushTool::draw_line(BBitmap* buffer, BPoint start,BPoint end,uint32 color) | |||
210 | { | |||
211 | int32 brush_width_per_2 = (int32)floor(brush->Width()/2); | |||
212 | int32 brush_height_per_2 = (int32)floor(brush->Height()/2); | |||
213 | BRect a_rect = MakeRectFromPoints(start, end); | |||
214 | a_rect.InsetBy(-brush_width_per_2-1,-brush_height_per_2-1); | |||
215 | // first check whether the line is longer in x direction than y | |||
216 | bool increase_x = fabs(start.x - end.x) >= fabs(start.y - end.y); | |||
217 | // check which direction the line is going | |||
218 | float sign_x; | |||
219 | float sign_y; | |||
220 | int32 number_of_points; | |||
221 | if ((end.x-start.x) != 0) { | |||
222 | sign_x = (end.x-start.x)/fabs(start.x - end.x); | |||
223 | } | |||
224 | else { | |||
225 | sign_x = 0; | |||
226 | } | |||
227 | if ((end.y-start.y) != 0) { | |||
228 | sign_y = (end.y-start.y)/fabs(start.y - end.y); | |||
229 | } | |||
230 | else { | |||
231 | sign_y = 0; | |||
232 | } | |||
233 | int32 dx,dy; | |||
234 | int32 last_x,last_y; | |||
235 | int32 new_x,new_y; | |||
236 | ||||
237 | if (increase_x) { | |||
238 | float y_add = ((float)fabs(start.y - end.y)) / ((float)fabs(start.x - end.x)); | |||
239 | number_of_points = (int32)fabs(start.x-end.x); | |||
240 | for (int32 i=0;i<number_of_points;i++) { | |||
241 | last_point = start; | |||
242 | start.x += sign_x; | |||
243 | start.y += sign_y * y_add; | |||
244 | new_x = (int32)round(start.x); | |||
245 | new_y = (int32)round(start.y); | |||
246 | last_x = (int32)round(last_point.x); | |||
247 | last_y = (int32)round(last_point.y); | |||
248 | ||||
249 | dx = new_x - last_x; | |||
250 | dy = new_y - last_y; | |||
251 | draw_brush(buffer, BPoint(new_x - brush_width_per_2, new_y - | |||
252 | brush_height_per_2), dx, dy, color); | |||
253 | ||||
254 | // view->Window()->Lock(); | |||
255 | // view->Invalidate(); | |||
256 | // view->Window()->Unlock(); | |||
257 | // snooze(50 * 1000); | |||
258 | } | |||
259 | } | |||
260 | ||||
261 | else { | |||
262 | float x_add = ((float)fabs(start.x - end.x)) / ((float)fabs(start.y - end.y)); | |||
263 | number_of_points = (int32)fabs(start.y-end.y); | |||
264 | for (int32 i=0;i<number_of_points;i++) { | |||
265 | last_point = start; | |||
266 | start.y += sign_y; | |||
267 | start.x += sign_x * x_add; | |||
268 | new_x = (int32)round(start.x); | |||
269 | new_y = (int32)round(start.y); | |||
270 | last_x = (int32)round(last_point.x); | |||
271 | last_y = (int32)round(last_point.y); | |||
272 | ||||
273 | dx = new_x - last_x; | |||
274 | dy = new_y - last_y; | |||
275 | draw_brush(buffer, BPoint(new_x-brush_width_per_2,new_y-brush_height_per_2),dx,dy,color); | |||
276 | ||||
277 | // view->Window()->Lock(); | |||
278 | // view->Invalidate(); | |||
279 | // view->Window()->Unlock(); | |||
280 | // snooze(50 * 1000); | |||
281 | } | |||
282 | } | |||
283 | return a_rect; | |||
284 | } | |||
285 | ||||
286 | ||||
287 | void | |||
288 | BrushTool::draw_brush(BBitmap* buffer, BPoint point, | |||
289 | int32 dx, int32 dy, uint32 c) | |||
290 | { | |||
291 | span* spans; | |||
292 | int32 px = (int32)point.x; | |||
293 | int32 py = (int32)point.y; | |||
294 | uint32** brush_matrix = brush->GetData(&spans, dx, dy); | |||
295 | ||||
296 | bits = (uint32*)buffer->Bits(); | |||
297 | uint32* target_bits = bits; | |||
298 | while ((spans != NULL__null) && (spans->row + py <= bottom_bound)) { | |||
299 | int32 left = max_c(px + spans->span_start, left_bound)((px + spans->span_start)>(left_bound)?(px + spans-> span_start):(left_bound)) ; | |||
300 | int32 right = min_c(px + spans->span_end, right_bound)((px + spans->span_end)>(right_bound)?(right_bound):(px + spans->span_end)); | |||
301 | int32 y = spans->row; | |||
302 | if (y + py >= top_bound) { | |||
303 | // This works even if there are many spans in one row. | |||
304 | target_bits = bits + (y + py) * bpr + left; | |||
305 | for (int32 x = left; x <= right; ++x) { | |||
306 | if (selection->IsEmpty() || selection->ContainsPoint(x, y + py)) { | |||
307 | ||||
308 | *target_bits = mix_2_pixels_fixed(c, *target_bits, | |||
309 | brush_matrix[y][x-px]); | |||
310 | } | |||
311 | target_bits++; | |||
312 | } | |||
313 | } | |||
314 | spans = spans->next; | |||
315 | } | |||
316 | } | |||
317 | ||||
318 | ||||
319 | status_t | |||
320 | BrushTool::readSettings(BFile &file, bool isLittleEndian) | |||
321 | { | |||
322 | int32 length; | |||
323 | if (file.Read(&length,sizeof(int32)) != sizeof(int32)) | |||
324 | return B_ERROR(-1); | |||
325 | ||||
326 | if (isLittleEndian) | |||
327 | length = B_LENDIAN_TO_HOST_INT32(length)(uint32)(length); | |||
328 | else | |||
329 | length = B_BENDIAN_TO_HOST_INT32(length)(uint32)__builtin_bswap32(length); | |||
330 | ||||
331 | int32 version; | |||
332 | if (file.Read(&version,sizeof(int32)) != sizeof(int32)) | |||
333 | return B_ERROR(-1); | |||
334 | ||||
335 | if (isLittleEndian) | |||
336 | version = B_LENDIAN_TO_HOST_INT32(version)(uint32)(version); | |||
337 | else | |||
338 | version = B_BENDIAN_TO_HOST_INT32(version)(uint32)__builtin_bswap32(version); | |||
339 | ||||
340 | if (version != TOOL_SETTINGS_STRUCT_VERSION0x00000001) { | |||
341 | file.Seek(length - sizeof(int32), SEEK_CUR1); | |||
342 | return B_ERROR(-1); | |||
343 | } | |||
344 | ||||
345 | // Here we should take the endianness into account. | |||
346 | brush_info info; | |||
347 | if (file.Read(&info, sizeof(struct brush_info)) != sizeof(struct brush_info)) | |||
348 | return B_ERROR(-1); | |||
349 | ||||
350 | delete brush; | |||
351 | brush = new Brush(info); | |||
352 | ||||
353 | return B_OK((int)0); | |||
354 | } | |||
355 | ||||
356 | ||||
357 | status_t | |||
358 | BrushTool::writeSettings(BFile &file) | |||
359 | { | |||
360 | int32 type = Type(); | |||
361 | if (file.Write(&type, sizeof(int32)) != sizeof(int32)) | |||
362 | return B_ERROR(-1); | |||
363 | ||||
364 | int32 settings_size = sizeof(struct brush_info) + sizeof(int32); | |||
365 | if (file.Write(&settings_size,sizeof(int32)) != sizeof(int32)) | |||
366 | return B_ERROR(-1); | |||
367 | ||||
368 | int32 settings_version = TOOL_SETTINGS_STRUCT_VERSION0x00000001; | |||
369 | if (file.Write(&settings_version,sizeof(int32)) != sizeof(int32)) | |||
370 | return B_ERROR(-1); | |||
371 | ||||
372 | brush_info info; | |||
373 | info = brush->GetInfo(); | |||
374 | if (file.Write(&info,sizeof(struct brush_info)) != sizeof(struct brush_info)) | |||
375 | return B_ERROR(-1); | |||
376 | ||||
377 | return B_OK((int)0); | |||
378 | } | |||
379 | ||||
380 | ||||
381 | // #pragma mark -- BrushToolConfigView | |||
382 | ||||
383 | ||||
384 | BrushToolConfigView::BrushToolConfigView(DrawingTool* tool) | |||
385 | : DrawingToolConfigView(tool) | |||
386 | { | |||
387 | if (BLayout* layout = GetLayout()) { | |||
388 | BrushTool* brushTool = dynamic_cast<BrushTool*> (tool); | |||
389 | layout->AddView(BrushEditor::CreateBrushEditor(brushTool->GetBrush())); | |||
390 | } | |||
391 | } |