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