File: | home/HaikuArchives/ArtPaint/artpaint/tools/BrushTool.cpp |
Warning: | line 297, 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 = 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; |
Value stored to 'target_bits' during its initialization is never read | |
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 | } |