Bug Summary

File:home/HaikuArchives/ArtPaint/artpaint/tools/BitmapDrawer.cpp
Warning:line 651, column 9
Value stored to 'bottom_y' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-haiku -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name BitmapDrawer.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /boot/system/lib/clang/12.0.1 -iquote ./ -iquote artpaint/ -iquote artpaint/Utilities/ -iquote artpaint/application/ -iquote artpaint/controls/ -iquote artpaint/layers/ -iquote artpaint/paintwindow/ -iquote artpaint/tools/ -iquote artpaint/viewmanipulators/ -iquote artpaint/windows/ -iquote objects_artpaint/ -isystem /boot/system/develop/headers/private/interface -internal-isystem /system/develop/headers/c++ -internal-isystem /system/develop/headers/c++/x86_64-unknown-haiku -internal-isystem /system/develop/headers/c++/backward -O3 -fdeprecated-macro -fdebug-compilation-dir /boot/home/HaikuArchives/ArtPaint -ferror-limit 19 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /tmp/scan-build-2022-07-02-122529-1240-1 -x c++ artpaint/tools/BitmapDrawer.cpp
1/*
2 * Copyright 2003, Heikki Suhonen
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Heikki Suhonen <heikki.suhonen@gmail.com>
7 * Dale Cieslak <dcieslak@yahoo.com>
8 *
9 */
10#include <stdio.h>
11#include <algorithm>
12
13
14#include "BitmapDrawer.h"
15#include "HSPolygon.h"
16#include "PixelOperations.h"
17#include "Selection.h"
18
19
20BitmapDrawer::BitmapDrawer(BBitmap *bitmap)
21{
22 bitmap_bounds = bitmap->Bounds();
23
24 bitmap_bits = (uint32*)bitmap->Bits();
25 bitmap_bpr = bitmap->BytesPerRow()/4;
26 bitmap_data_length = bitmap->BitsLength();
27}
28
29
30status_t
31BitmapDrawer::DrawHairLine(BPoint start, BPoint end, uint32 color,
32 bool anti_alias, Selection *sel,
33 uint32 (*composite_func)(uint32, uint32))
34{
35 // This function only draws lines with width of 1.
36 // Always draw the lines from left to right or from top to bottom.
37 float start_x = min_c(start.x,end.x)((start.x)>(end.x)?(end.x):(start.x));
38 float start_y = min_c(start.y,end.y)((start.y)>(end.y)?(end.y):(start.y));
39
40 float end_x = max_c(start.x,end.x)((start.x)>(end.x)?(start.x):(end.x));
41 float end_y = max_c(start.y,end.y)((start.y)>(end.y)?(start.y):(end.y));
42 float dx = end_x - start_x;
43 float dy = end_y - start_y;
44 float sign_y = 0.0, sign_x = 0.0;
45 if (dx > dy) {
46 if (end.y != start.y)
47 sign_y = (start_x == start.x ? (end.y - start.y)/fabs(start.y-end.y) : (start.y - end.y)/fabs(end.y-start.y));
48 else
49 sign_y = 0;
50 }
51 else {
52 if (start.x != end.x)
53 sign_x = (start_y == start.y ? (end.x - start.x)/fabs(end.x-start.x) : (start.x - end.x)/fabs(start.x-end.x));
54 else
55 sign_x = 0;
56 }
57 uint32 old_value;
58 uint32 new_value;
59
60 if (anti_alias == TRUE1) {
61 // Here we should take the line's equation and draw with Wu's algorithm.
62 if (dx > dy) {
63 // Draw the line horizontally. For every x-coordinate we mix the color with
64 // two pixels at positions x,floor(y) and x,ceil(y).
65 float step_y = sign_y*dy/dx;
66 float y = ( (start_x == start.x) ? start.y : end.y);
67 float y_mix_upper,y_mix_lower;
68
69 for (float x=start_x;x<=end_x;x++) {
70 y_mix_upper = y-floor(y);
71 y_mix_lower = 1.0 - y_mix_upper;
72
73 // This is the real Wu's two point anti-aliasing scheme.
74 new_value = ((uint32)(( (color >> 24) & 0xFF) * y_mix_upper) << 24) |
75 ((uint32)(( (color >> 16) & 0xFF) * y_mix_upper) << 16) |
76 ((uint32)(( (color >> 8) & 0xFF) * y_mix_upper) << 8) |
77 ((uint32)(( (color ) & 0xFF) * y_mix_upper) );
78 SetPixel(BPoint(x,ceil(y)), new_value, sel);
79 new_value = ((uint32)(( (color >> 24) & 0xFF) * y_mix_lower) << 24) |
80 ((uint32)(( (color >> 16) & 0xFF) * y_mix_lower) << 16) |
81 ((uint32)(( (color >> 8) & 0xFF) * y_mix_lower) << 8) |
82 ((uint32)(( (color ) & 0xFF) * y_mix_lower) );
83 SetPixel(BPoint(x,floor(y)), new_value, sel, composite_func);
84 y += step_y;
85 }
86 }
87 else {
88 // Draw the line vertically.
89 float step_x = sign_x*dx/dy;
90 float x = ( (start_y == start.y) ? start.x : end.x);
91 float x_mix_left,x_mix_right;
92
93 for (float y=start_y;y<=end_y;y++) {
94 x_mix_left = ceil(x)-x;
95 x_mix_right = 1.0 - x_mix_left;
96
97 // This is the real Wu's two point anti-aliasing scheme.
98 new_value = ((uint32)(( (color >> 24) & 0xFF) * x_mix_right) << 24) |
99 ((uint32)(( (color >> 16) & 0xFF) * x_mix_right) << 16) |
100 ((uint32)(( (color >> 8) & 0xFF) * x_mix_right) << 8) |
101 ((uint32)(( (color ) & 0xFF) * x_mix_right) );
102 SetPixel(BPoint(ceil(x),y),new_value, sel);
103 new_value = ((uint32)(( (color >> 24) & 0xFF) * x_mix_left) << 24) |
104 ((uint32)(( (color >> 16) & 0xFF) * x_mix_left) << 16) |
105 ((uint32)(( (color >> 8) & 0xFF) * x_mix_left) << 8) |
106 ((uint32)(( (color ) & 0xFF) * x_mix_left) );
107 SetPixel(BPoint(floor(x),y),new_value, sel, composite_func);
108
109 x += step_x;
110 }
111 }
112 }
113 else {
114 // use DDA-algorithm to calculate line between the two argument points
115 // first check whether the line is longer in x direction than y
116 bool increase_x = fabs(start.x - end.x) >= fabs(start.y - end.y);
117 // check which direction the line is going
118 float sign_x;
119 float sign_y;
120
121 if ((end.x-start.x) != 0) {
122 sign_x = (end.x-start.x)/fabs(end.x-start.x);
123 }
124 else {
125 sign_x = 0;
126 }
127 if ((end.y-start.y) != 0) {
128 sign_y = (end.y-start.y)/fabs(end.y-start.y);
129 }
130 else {
131 sign_y = 0;
132 }
133
134 if (increase_x) {
135 // allocate the point-list
136 int32 number_of_points = (int32)fabs(start.x - end.x) + 1;
137 float y_add = ((float)fabs(start.y - end.y)) / ((float)fabs(start.x - end.x));
138 for (int32 i=0;i < number_of_points;i++) {
139 SetPixel(start, color, sel, composite_func);
140
141 start.x += sign_x;
142 start.y += sign_y * y_add;
143 }
144 }
145
146 else {
147 int32 number_of_points = (int32)fabs(start.y - end.y) + 1;
148 float x_add = ((float)fabs(start.x - end.x)) / ((float)fabs(start.y - end.y));
149 for (int32 i=0;i < number_of_points;i++) {
150 SetPixel(start, color, sel, composite_func);
151
152 start.y += sign_y;
153 start.x += sign_x * x_add;
154 }
155 }
156 }
157
158 return B_OK((int)0);
159}
160
161
162status_t
163BitmapDrawer::DrawLine(BPoint start, BPoint end, uint32 color, float width,
164 bool anti_alias, Selection *sel,
165 uint32 (*composite_func)(uint32, uint32))
166{
167 // The line width is split in to two parts
168 float distance1_from_center = ceil((width - 1.0) / 2.0);
169 float distance2_from_center = floor((width - 1.0) / 2.0);
170
171 // This function hangs when the start and end points were the same.
172 if (start == end)
173 return B_ERROR(-1);
174
175 // Then we take the normal vector of (end - start)by using cross product.
176 // Let's pretend that a = (end-start) is a vector in three dimensional
177 // vector space. The normal for it (in two dimensions) can be obtained by:
178 //
179 // | i j k |
180 // a'xa = | a'.x a'.y 1 | = (a'.y*0 - 1*a.y)i - (a'.x*0 - 1*a.x)k + (a'.x*a.y - a'.y*a.x)k
181 // | a.x a.y 0 |
182 //
183 // We then ignore the k component.
184 BPoint normal;
185 normal.x = -(end-start).y;
186 normal.y = (end-start).x;
187
188 // Then we normalize the normal vector
189 float normal_vector_length = sqrt((normal.x*normal.x)+(normal.y*normal.y));
190 normal.x = normal.x/normal_vector_length;
191 normal.y = normal.y/normal_vector_length;
192
193 // Change the normal vector to point upward.
194 if (normal.y < 0) {
195 normal = BPoint(0,0)-normal;
196 }
197
198 BPoint normal1;
199 BPoint normal2;
200
201 normal1.x = distance1_from_center * normal.x;
202 normal1.y = distance1_from_center * normal.y;
203 normal2.x = distance2_from_center * normal.x;
204 normal2.y = distance2_from_center * normal.y;
205
206 // Then we add and subtract the normal vector multiplied by scalars of width from
207 // the end and start-points to get the four corners of our rectangle.
208 BPoint point_list[4];
209 point_list[0] = start + normal1;
210 point_list[1] = end + normal1;
211 point_list[2] = end - normal2;
212 point_list[3] = start - normal2;
213
214// HSPolygon *poly = new HSPolygon(point_list,4);
215// poly->RoundToInteger();
216
217 // Then we fill the rectangle.
218 DrawRectanglePolygon(point_list,color, TRUE1, anti_alias, sel, composite_func);
219// DrawConvexPolygon(poly->GetPointList(),poly->GetPointCount(),color,TRUE,anti_alias);
220
221// delete poly;
222
223 return B_OK((int)0);
224}
225
226
227status_t
228BitmapDrawer::DrawCircle(BPoint center, float radius, uint32 color,
229 bool fill, bool anti_alias, Selection *sel,
230 uint32 (*composite_func)(uint32, uint32))
231{
232 // For the moment we only do non-anti-aliased circles. So radius should be a whole number.
233
234 BRect circleRect(center.x-radius, center.y-radius, center.x+radius, center.y+radius);
235 DrawEllipse(circleRect, color, fill, anti_alias, sel, composite_func);
236
237 return B_OK((int)0);
238}
239
240
241status_t
242BitmapDrawer::DrawEllipse(BRect rect, uint32 color,
243 bool fill, bool anti_alias, Selection *sel,
244 uint32 (*composite_func)(uint32, uint32))
245{
246 BPoint center;
247 center.x = floor(rect.left + (rect.right-rect.left)/2.0);
248 center.y = floor(rect.top + (rect.bottom-rect.top)/2.0);
249
250 uint32 radius1 = rect.Width()/2.;
251 uint32 radius2 = rect.Height()/2.;
252
253 uint32 radiusSqr = radius1*radius1;
254 uint32 radius2Sqr = radius2*radius2;
255
256 int32 quarter = round(max_c(radiusSqr, radius2Sqr)((radiusSqr)>(radius2Sqr)?(radiusSqr):(radius2Sqr)) / sqrt(radiusSqr+radius2Sqr));
257
258 int32 xmax = min_c(quarter, radius1)((quarter)>(radius1)?(radius1):(quarter));
259 int32 ymax = min_c(quarter, radius2)((quarter)>(radius2)?(radius2):(quarter));
260 for (int32 x = 0; x <= xmax; ++x) {
261 float y = radius2 * sqrt(1.-(float)(x*x)/(float)(radiusSqr));
262 float error = y - floor(y);
263
264 union {
265 uint8 bytes[4];
266 uint32 word;
267 } color1, color2;
268
269 color1.word = color;
270 color2.word = color;
271
272 uint8 alpha = round((1.0 - error) * color1.bytes[3]);
273
274 color1.bytes[3] = alpha;
275 color2.bytes[3] -= alpha;
276
277 if (fill) {
278 if (anti_alias == TRUE1)
279 SetMirroredPixels(center, x, floor(y)+1, color2.word, sel,
280 composite_func);
281 if (x != 0)
282 FillColumn(center, x, 1, floor(y), color, sel, composite_func);
283 } else {
284 if (anti_alias == TRUE1) {
285 SetMirroredPixels(center, x, floor(y), color1.word, sel,
286 composite_func);
287 SetMirroredPixels(center, x, floor(y)+1, color2.word, sel,
288 composite_func);
289 } else {
290 SetMirroredPixels(center, x, y, color, sel, composite_func);
291 }
292 }
293 }
294
295 for (int32 y = 0; y <= ymax; ++y) {
296 float x = radius1 * sqrt(1.-(float)(y*y)/(float)(radius2Sqr));
297 float error = x - floor(x);
298
299 union {
300 uint8 bytes[4];
301 uint32 word;
302 } color1, color2;
303
304 color1.word = color;
305 color2.word = color;
306
307 uint8 alpha = round((1.0 - error) * color1.bytes[3]);
308
309 color1.bytes[3] = alpha;
310 color2.bytes[3] -= alpha;
311
312 if (fill) {
313 if (anti_alias == TRUE1)
314 SetMirroredPixels(center, floor(x)+1, y, color2.word, sel,
315 composite_func);
316 if (y != 0)
317 FillRow(center, quarter+1, floor(x), y, color, sel,
318 composite_func);
319 } else {
320 if (anti_alias == TRUE1) {
321 SetMirroredPixels(center, floor(x), y, color1.word, sel,
322 composite_func);
323 SetMirroredPixels(center, floor(x)+1, y, color2.word, sel,
324 composite_func);
325 } else {
326 SetMirroredPixels(center, x, y, color, sel, composite_func);
327 }
328 }
329 }
330
331 if (fill) {
332 FillRow(center, 1, radius1, 0, color, sel, composite_func);
333 FillColumn(center, 0, 1, radius2, color, sel, composite_func);
334 SetPixel(center, color, sel, composite_func);
335 }
336
337 return B_OK((int)0);
338}
339
340
341// This function is quite useless unless we want draw a rectangular bitmap such that the data
342// reaches borders at every position and it is binary data.
343status_t
344BitmapDrawer::DrawBitmap(BBitmap *bitmap, BRect bounds, BRect exclude,bool)
345{
346 // The exclude rect should be the same size as bounds but with a different offset.
347 // This will copy a bitmap to the actual bitmap
348 uint32 *target_bits;
349 uint32 *bits = (uint32*)bitmap->Bits();
350 int32 bitmap_width = bitmap->Bounds().IntegerWidth();
351
352 // Divide the bounds into two rectangles.
353 BRect area1 = bounds;
354 if (exclude.IsValid() == TRUE1) {
355 if (exclude.top > bounds.top) {
356 area1.top = bounds.top;
357 area1.bottom = exclude.top-1;
358 }
359 else {
360 area1.top = exclude.bottom+1;
361 area1.bottom = bounds.bottom;
362 }
363 area1.left = bounds.left;
364 area1.right = bounds.right;
365 }
366 area1 = area1 & bitmap_bounds;
367
368 target_bits = bitmap_bits + (int32)area1.left + (int32)area1.top * bitmap_bpr;
369 int32 area_width = area1.IntegerWidth();
370 int32 area_height = area1.IntegerHeight();
371 for (int32 y=0;y<=area_height;y++) {
372 for (int32 x=0;x<=area_width;x++) {
373 *target_bits++ = *bits++;
374 }
375 target_bits += bitmap_bpr - area_width - 1;
376 bits += bitmap_width - area_width;
377 }
378
379 BRect area2 = bounds;
380 if (area1 != (bounds & bitmap_bounds)) {
381 if (exclude.IsValid() == TRUE1) {
382 if (exclude.left > bounds.left) {
383 area2.left = bounds.left;
384 area2.right = exclude.left-1;
385 }
386 else {
387 area2.left = exclude.right+1;
388 area2.right = bounds.right;
389 }
390 area2.top = (area1.bottom < exclude.top ? area1.bottom + 1 : bounds.top);
391 area2.bottom = (area1.top > exclude.bottom ? area1.top - 1 : bounds.bottom);
392 }
393 area2 = area2 & bitmap_bounds;
394
395 target_bits = bitmap_bits + (int32)area2.left + (int32)area2.top * bitmap_bpr;
396 bits = (uint32*)bitmap->Bits();
397 area_width = area2.IntegerWidth();
398 area_height = area2.IntegerHeight();
399 for (int32 y=0;y<=area_height;y++) {
400 for (int32 x=0;x<=area_width;x++) {
401 *target_bits++ = *bits++;
402 }
403 target_bits += bitmap_bpr - area_width - 1;
404 bits += bitmap_width - area_width;
405 }
406 }
407 return B_OK((int)0);
408}
409
410
411status_t
412BitmapDrawer::DrawConvexPolygon(BPoint *point_list, int32 point_count,
413 uint32 color, bool fill, bool anti_alias)
414{
415 if (fill == FALSE0) {
416 // Just connect the corners with lines.
417 for (int32 i=0;i<point_count-1;i++) {
418 DrawHairLine(point_list[i], point_list[i+1], color, anti_alias);
419 }
420 DrawHairLine(point_list[point_count-1], point_list[0], color, anti_alias);
421 }
422 else /*if (anti_aliasing == FALSE) */ {
423 // We have to fill the polygon.
424 // We use the following method:
425 // 1. Determine the minimum y and maximum y coordinates of the polygon.
426 // 2. For each y-coordinate within the polygon find the two lines
427 // that cross the y-coordinate.
428 // 3. For those two found lines calculate the x-coordinates at y-position.
429 // 4. Select the minimum and maximum of those x-coordinates.
430 // 5. Fill the line at y-coordinate between minimum x and maximum x.
431 float min_y=1000000,max_y=-1000000;
432 for (int32 i=0;i<point_count;i++) {
433 min_y = min_c(point_list[i].y, min_y)((point_list[i].y)>(min_y)?(min_y):(point_list[i].y));
434 max_y = max_c(point_list[i].y, max_y)((point_list[i].y)>(max_y)?(point_list[i].y):(max_y));
435 }
436
437 // Round the mimimum and maximum y to the nearest integer.
438 min_y = ( ((min_y-floor(min_y)) < 0.5 ) ? floor(min_y) : ceil(min_y) );
439 max_y = ( ((max_y-floor(min_y)) < 0.5 ) ? floor(max_y) : ceil(max_y) );
440
441 for (int32 y=(int32)min_y;y<=max_y;y++) {
442 float min_x=1000000,max_x=-1000000;
443 int32 i=0,found_lines=0;
444
445 // We have to examine at least three lines because otherwise lines beginning at
446 // a the same corner-point might be the only found lines that cross certain y-row.
447 while ( (found_lines < 3) && (i<(point_count-1)) ) {
448 if ( ((point_list[i].y<=y) && (point_list[i+1].y >= y)) || ((point_list[i].y>=y) && (point_list[i+1].y <= y)) ) {
449 found_lines++;
450 min_x = min_c(min_x,MinimumCrossingPoint(point_list[i],point_list[i+1],y))((min_x)>(MinimumCrossingPoint(point_list[i],point_list[i+
1],y))?(MinimumCrossingPoint(point_list[i],point_list[i+1],y)
):(min_x))
;
451 max_x = max_c(max_x,MaximumCrossingPoint(point_list[i],point_list[i+1],y))((max_x)>(MaximumCrossingPoint(point_list[i],point_list[i+
1],y))?(max_x):(MaximumCrossingPoint(point_list[i],point_list
[i+1],y)))
;
452 }
453 i++;
454 }
455 if (found_lines < 3) {
456 if (((point_list[0].y<=y) && (point_list[point_count-1].y >= y)) || ((point_list[0].y>=y) && (point_list[point_count-1].y <= y)) ) {
457 found_lines++;
458 min_x = min_c(min_x,MinimumCrossingPoint(point_list[0],point_list[point_count-1],y))((min_x)>(MinimumCrossingPoint(point_list[0],point_list[point_count
-1],y))?(MinimumCrossingPoint(point_list[0],point_list[point_count
-1],y)):(min_x))
;
459 max_x = max_c(max_x,MaximumCrossingPoint(point_list[0],point_list[point_count-1],y))((max_x)>(MaximumCrossingPoint(point_list[0],point_list[point_count
-1],y))?(max_x):(MaximumCrossingPoint(point_list[0],point_list
[point_count-1],y)))
;
460 }
461 }
462 if (found_lines == 0) {
463 // We should not fill any pixels in this line
464 min_x = 1;
465 max_x = 0;
466 }
467 // Then round the minimum and maximum x to nearest integers.
468 min_x = ( ((min_x-floor(min_x)) < 0.5 ) ? floor(min_x) : ceil(min_x) );
469 max_x = ( ((max_x-floor(min_x)) < 0.5 ) ? floor(max_x) : ceil(max_x) );
470
471 // Then fill the span
472 // First round the minimum and maximum x to nearest integers.
473 min_x = ( ((min_x-floor(min_x)) < 0.5 ) ? floor(min_x) : ceil(min_x) );
474 max_x = ( ((max_x-floor(min_x)) < 0.5 ) ? floor(max_x) : ceil(max_x) );
475 for (int32 x=(int32)min_x;x<=max_x;x++) {
476 SetPixel(BPoint(x,y),color);
477 }
478 }
479 }
480 /* else {
481
482 }*/
483
484 return B_OK((int)0);
485}
486
487
488float
489BitmapDrawer::MinimumCrossingPoint(BPoint &start, BPoint &end, int32 y)
490{
491 // If the line is more vertical than horizontal there is only one point
492 // at coordinate y.
493 if (fabs(start.y-end.y) >= fabs(start.x-end.x)) {
494 // Now we just have to return the point at that location.
495 float step_x = (end.x-start.x)/fabs(start.y-end.y);
496 return start.x + fabs(start.y-y)*step_x;
497 }
498 else {
499 float step_y = (start.y-end.y)/fabs(start.x-end.x);
500 if (step_y != 0) {
501 float dir_x = (end.x-start.x)/fabs(start.x-end.x);
502 float x_add = fabs((fabs(start.y-y)-0.5)/step_y);
503 float x1 = start.x + dir_x*x_add;
504 x_add = fabs((fabs(start.y-y)+0.5)/step_y);
505 float x2 = start.x + dir_x*x_add;
506 return max_c(min_c(start.x,end.x),min_c(x1,x2))((((start.x)>(end.x)?(end.x):(start.x)))>(((x1)>(x2)
?(x2):(x1)))?(((start.x)>(end.x)?(end.x):(start.x))):(((x1
)>(x2)?(x2):(x1))))
;
507 }
508 else
509 return min_c(start.x,end.x)((start.x)>(end.x)?(end.x):(start.x));
510 }
511}
512
513
514float
515BitmapDrawer::MaximumCrossingPoint(BPoint &start, BPoint &end, int32 y)
516{
517 // If the line is more vertical than horizontal there is only one point
518 // at coordinate y.
519 if (fabs(start.y-end.y) >= fabs(start.x-end.x)) {
520 // Now we just have to return the point at that location.
521 float step_x = (end.x-start.x)/fabs(start.y-end.y);
522 return start.x + fabs(start.y-y)*step_x;
523 }
524 else {
525 float step_y = (start.y-end.y)/fabs(start.x-end.x);
526 if (step_y != 0) {
527 float dir_x = (end.x-start.x)/fabs(start.x-end.x);
528 float x_add = fabs((fabs(start.y-y)-0.5)/step_y);
529 float x1 = start.x + dir_x*x_add;
530 x_add = fabs((fabs(start.y-y)+0.5)/step_y);
531 float x2 = start.x + dir_x*x_add;
532 return min_c(max_c(start.x,end.x),max_c(x1,x2))((((start.x)>(end.x)?(start.x):(end.x)))>(((x1)>(x2)
?(x1):(x2)))?(((x1)>(x2)?(x1):(x2))):(((start.x)>(end.x
)?(start.x):(end.x))))
;
533 }
534 else
535 return max_c(start.x,end.x)((start.x)>(end.x)?(start.x):(end.x));
536 }
537}
538
539
540status_t
541BitmapDrawer::DrawRectanglePolygon(BPoint *corners, uint32 color,
542 bool fill, bool anti_alias, Selection *sel,
543 uint32 (*composite_func)(uint32, uint32))
544{
545 // This is a special-case of the convex-polygon function that draws polygons that are rectangular.
546 // In addition to the convex polygon case we can use the following simplifications:
547 // 1. The rectangle has two pairs of parallel lines.
548 // 2. Rectangle is symmetric; point at (x,y) is same as point at (-x,-y)
549 // when the origo is at polygons center.
550 // 3. If one of the polygon's lines has the same x or y coordinate at both ends,
551 // the polygon can be drawn very quickly.
552 // 4. If the case 3 does not apply we can select two lines that begin from top point
553 // and fill the spans between them. When the other line ends we can select the other line
554 // that begins at the point where the line ended. If we draw symmetrically we can stop when
555 // we have reached the middle-height of rectangle.
556 // 5. If case 3 does not apply then every corner has one extreme value.
557
558 if (fill == FALSE0) {
559 // Just connect the corners with lines.
560 // First round the corners to proper values.
561 corners[0].x = round(corners[0].x);
562 corners[0].y = round(corners[0].y);
563 corners[1].x = round(corners[1].x);
564 corners[1].y = round(corners[1].y);
565 corners[2].x = round(corners[2].x);
566 corners[2].y = round(corners[2].y);
567 corners[3].x = round(corners[3].x);
568 corners[3].y = round(corners[3].y);
569
570 DrawHairLine(corners[0], corners[1], color, anti_alias, sel, composite_func);
571 DrawHairLine(corners[1], corners[2], color, anti_alias, sel, composite_func);
572 DrawHairLine(corners[2], corners[3], color, anti_alias, sel, composite_func);
573 DrawHairLine(corners[3], corners[0], color, anti_alias, sel, composite_func);
574 }
575 else {
576 if (anti_alias == TRUE1) {
577 FillAntiAliasedRectangle(corners, color, sel, composite_func);
578 }
579 else {
580 FillRectangle(corners, color, sel, composite_func);
581 }
582 }
583
584 return B_OK((int)0);
585}
586
587
588status_t
589BitmapDrawer::FillAntiAliasedRectangle(BPoint *corners, uint32 color,
590 Selection *sel, uint32 (*composite_func)(uint32, uint32))
591{
592 // If the rectangle is aligned with the coordinate axis we do not need to
593 // do much.
594 if ((corners[0].x == corners[1].x) || (corners[0].y == corners[1].y)) {
595 // Select minimum and maximum coordinates.
596 int32 min_x = (int32)round(min_c(corners[0].x, corners[2].x)((corners[0].x)>(corners[2].x)?(corners[2].x):(corners[0].
x))
);
597 int32 max_x = (int32)round(max_c(corners[0].x, corners[2].x)((corners[0].x)>(corners[2].x)?(corners[0].x):(corners[2].
x))
);
598 int32 min_y = (int32)round(min_c(corners[0].y, corners[2].y)((corners[0].y)>(corners[2].y)?(corners[2].y):(corners[0].
y))
);
599 int32 max_y = (int32)round(max_c(corners[0].y, corners[2].y)((corners[0].y)>(corners[2].y)?(corners[0].y):(corners[2].
y))
);
600
601 for (int32 y=min_y;y<=max_y;y++) {
602 for (int32 x=min_x;x<=max_x;x++) {
603 SetPixel(BPoint(x,y), color, sel, composite_func);
604 }
605 }
606 }
607 // If the rectangle is not rectilinear we must sort the points
608 // and then fill the resulting rectangular polygon. This is almost
609 // exact copy of non-antialiased fill, but we use a subppixel mask to
610 // determine the coverage of each pixel.
611 else {
612 union {
613 unsigned char bytes[4];
614 uint32 word;
615 } norm_color;
616
617 norm_color.word = color;
618 uint8 alpha = norm_color.bytes[3];
619
620 // First we must sort the points.
621 //
622 // Top
623 // Left
624 // Right
625 // Bottom
626 BPoint left,right,top,bottom;
627 left = right = top = bottom = corners[0];
628 for (int32 i=0;i<4;i++) {
629 if (corners[i].x < left.x)
630 left = corners[i];
631 if (corners[i].x > right.x)
632 right = corners[i];
633 if (corners[i].y < top.y)
634 top = corners[i];
635 if (corners[i].y > bottom.y)
636 bottom = corners[i];
637 }
638 float span_left;
639 float span_right;
640 float left_diff;
641 float right_diff;
642 left_diff = (left.x - top.x) / (left.y - top.y);
643 right_diff = (right.x - top.x) / (right.y - top.y);
644
645 // These two values are used when calculating the subpixel coverages.
646 // These y-differences are positive.
647 float left_y_diff = (left.y - top.y) / (top.x - left.x);
648 float right_y_diff = (right.y - top.y) / (right.x - top.x);
649
650 float y = floor(top.y);
651 float bottom_y = floor(bottom.y);
Value stored to 'bottom_y' during its initialization is never read
652 span_left = (y - top.y) * left_diff + top.x;
653 span_right = (y - top.y) * right_diff + top.x;
654
655 float absolute_left = 0;
656 float absolute_right = bitmap_bounds.right;
657 float absolute_top = 0;
658 float absolute_bottom = bitmap_bounds.bottom;
659
660 bottom_y = min_c(left.y, right.y)((left.y)>(right.y)?(right.y):(left.y));
661
662 // This constant determines how many subpixels are used in one direction.
663 const float SUBPIXEL_AMOUNT = 13;
664
665 int32 coverage;
666 int32 max_coverage = 0;
667 // This loop is split into three parts to avoid
668 // having too many if-clauses inside the loop.
669 // Then there are also two versions of it: one without selections
670 // and one with selections.
671 if ((sel == NULL__null) || (sel->IsEmpty() == TRUE1)) {
672 while (y <= bottom_y) {
673
674 if ((y <= absolute_bottom) && (y >= absolute_top)) {
675 // int32 left_bound = max_c(ceil(span_left+left_diff),max_c(absolute_left,left.x));
676 // int32 right_bound = min_c(min_c(absolute_right,right.x),floor(span_right+right_diff));
677 int32 left_bound = (int32)max_c(floor(span_left+left_diff),max_c(absolute_left,floor(left.x)))((floor(span_left+left_diff))>(((absolute_left)>(floor(
left.x))?(absolute_left):(floor(left.x))))?(floor(span_left+left_diff
)):(((absolute_left)>(floor(left.x))?(absolute_left):(floor
(left.x)))))
;
678 int32 right_bound = (int32)min_c(min_c(absolute_right,ceil(right.x)),ceil(span_right+right_diff))((((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
)))>(ceil(span_right+right_diff))?(ceil(span_right+right_diff
)):(((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
))))
;
679 for (int32 x=left_bound;x<=right_bound;x++) {
680 coverage = 0;
681 if ( (((top.y) + (top.x - (x-0.5))*left_y_diff) > (y-0.5))
682 || (((top.y) + ((x+0.5) - top.x )*right_y_diff) > (y-0.5)) ) {
683 // First calculate the subpixel coverages for the point x,y.
684 for (float sub_y = y - 0.51;sub_y <= y+0.51; sub_y += 1.0/(SUBPIXEL_AMOUNT-1)) {
685 for (float sub_x = x - 0.51;sub_x <= x+0.51; sub_x += 1.0/(SUBPIXEL_AMOUNT-1)) {
686 if ( (((top.y) + (top.x - sub_x)*left_y_diff) <= sub_y)
687 && (((top.y) + (sub_x - top.x )*right_y_diff) <= sub_y) ) {
688 coverage++;
689 }
690 }
691 }
692 norm_color.bytes[3] = (uint8)(alpha*((float(coverage)) /
693 (SUBPIXEL_AMOUNT * SUBPIXEL_AMOUNT)));
694 SetPixel(x, int32(y), norm_color.word, sel, composite_func);
695 max_coverage = max_c(coverage, max_coverage)((coverage)>(max_coverage)?(coverage):(max_coverage));
696 }
697 else
698 SetPixel(x, int32(y), color, sel, composite_func);
699 }
700 }
701 y++;
702 span_left += left_diff;
703 span_right += right_diff;
704 }
705
706 bottom_y = max_c(left.y,right.y)((left.y)>(right.y)?(left.y):(right.y));
707
708 if ((y>=left.y) && (left_diff <= 0)) {
709 left_diff = (bottom.x - left.x)/(bottom.y - left.y);
710 span_left = (y - left.y)*left_diff + left.x;
711 left_y_diff = (bottom.y - left.y)/(bottom.x - left.x);
712
713 while (y <= bottom_y) {
714
715 if ((y<=absolute_bottom) && (y>=absolute_top)) {
716 // int32 left_bound = max_c(ceil(span_left-left_diff),max_c(absolute_left,left.x));
717 // int32 right_bound = min_c(min_c(absolute_right,right.x),floor(span_right+right_diff));
718 int32 left_bound = (int32)max_c(floor(span_left-left_diff),max_c(absolute_left,floor(left.x)))((floor(span_left-left_diff))>(((absolute_left)>(floor(
left.x))?(absolute_left):(floor(left.x))))?(floor(span_left-left_diff
)):(((absolute_left)>(floor(left.x))?(absolute_left):(floor
(left.x)))))
;
719 int32 right_bound = (int32)min_c(min_c(absolute_right,ceil(right.x)),ceil(span_right+right_diff))((((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
)))>(ceil(span_right+right_diff))?(ceil(span_right+right_diff
)):(((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
))))
;
720 for (int32 x=left_bound;x<=right_bound;x++) {
721 coverage = 0;
722
723 // We can calculate y-coordinates of the boundaries at any given
724 // x-coordinate by using the y_diffs
725 if ( (((left.y) + ((x-0.5)-left.x)*left_y_diff) < (y+0.5))
726 || (((top.y) + ((x+0.5) - top.x )*right_y_diff) > (y-0.5)) ) {
727 // First calculate the subpixel coverages for the point x,y.
728 for (float sub_y = y - 0.51;sub_y <= y+0.51; sub_y += 1.0/(SUBPIXEL_AMOUNT-1)) {
729 for (float sub_x = x - 0.51;sub_x <= x+0.51; sub_x += 1.0/(SUBPIXEL_AMOUNT-1)) {
730 if ( (((left.y) + (sub_x - left.x)*left_y_diff) >= sub_y)
731 && (((top.y) + (sub_x - top.x )*right_y_diff) <= sub_y) ) {
732 coverage++;
733 }
734 }
735 }
736 norm_color.bytes[3] = (uint8)(alpha*((float(coverage)) /
737 (SUBPIXEL_AMOUNT * SUBPIXEL_AMOUNT)));
738 SetPixel(x, int32(y), norm_color.word, sel, composite_func);
739 max_coverage = max_c(coverage,max_coverage)((coverage)>(max_coverage)?(coverage):(max_coverage));
740 }
741 else
742 SetPixel(x, int32(y), color, sel, composite_func);
743 }
744 }
745 y++;
746 span_left += left_diff;
747 span_right += right_diff;
748
749 }
750 }
751 else if ((y>=right.y) && (right_diff >= 0)) {
752 right_diff = (bottom.x - right.x)/(bottom.y - right.y);
753 span_right = (y - right.y)*right_diff + right.x;
754 right_y_diff = (bottom.y - right.y)/(right.x - bottom.x);
755
756 while (y <= bottom_y) {
757
758 if ((y<=absolute_bottom) && (y>=absolute_top)) {
759 // int32 left_bound = max_c(ceil(span_left+left_diff),max_c(absolute_left,left.x));
760 // int32 right_bound = min_c(min_c(absolute_right,right.x),floor(span_right-right_diff));
761 int32 left_bound = (int32)max_c(floor(span_left+left_diff),max_c(absolute_left,floor(left.x)))((floor(span_left+left_diff))>(((absolute_left)>(floor(
left.x))?(absolute_left):(floor(left.x))))?(floor(span_left+left_diff
)):(((absolute_left)>(floor(left.x))?(absolute_left):(floor
(left.x)))))
;
762 int32 right_bound = (int32)min_c(min_c(absolute_right,ceil(right.x)),ceil(span_right-right_diff))((((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
)))>(ceil(span_right-right_diff))?(ceil(span_right-right_diff
)):(((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
))))
;
763 for (int32 x=left_bound;x<=right_bound;x++) {
764 coverage = 0;
765 if ( (((top.y) + (top.x - (x-0.5))*left_y_diff) > (y-0.5))
766 || (((right.y) + (right.x - (x+0.5))*right_y_diff) < (y+0.5)) ) {
767 // First calculate the subpixel coverages for the point x,y.
768 for (float sub_y = y - 0.51;sub_y <= y+0.51; sub_y += 1.0/(SUBPIXEL_AMOUNT-1)) {
769 for (float sub_x = x - 0.51;sub_x <= x+0.51; sub_x += 1.0/(SUBPIXEL_AMOUNT-1)) {
770 if ( (((top.y) + (top.x - sub_x)*left_y_diff) <= sub_y)
771 && (((right.y) + (right.x - sub_x)*right_y_diff) > sub_y) ) {
772 coverage++;
773 }
774 }
775 }
776 norm_color.bytes[3] = (uint8)(alpha*((float(coverage)) /
777 (SUBPIXEL_AMOUNT * SUBPIXEL_AMOUNT)));
778 SetPixel(x, int32(y), norm_color.word, sel, composite_func);
779 max_coverage = max_c(coverage, max_coverage)((coverage)>(max_coverage)?(coverage):(max_coverage));
780 }
781 else
782 SetPixel(x, int32(y), color, sel, composite_func);
783 }
784 }
785 y++;
786 span_left += left_diff;
787 span_right += right_diff;
788
789 }
790 }
791
792 bottom_y = ceil(bottom.y);
793 if ((y>=left.y) && (left_diff <= 0)) {
794 left_diff = (bottom.x - left.x)/(bottom.y - left.y);
795 span_left = (y - left.y)*left_diff + left.x;
796 left_y_diff = (bottom.y - left.y)/(bottom.x - left.x);
797 }
798 if ((y>=right.y) && (right_diff >= 0)) {
799 right_diff = (bottom.x - right.x)/(bottom.y - right.y);
800 span_right = (y - right.y)*right_diff + right.x;
801 right_y_diff = (bottom.y - right.y)/(right.x - bottom.x);
802 }
803
804 while (y <= bottom_y) {
805
806 if ((y<=absolute_bottom) && (y>=absolute_top)) {
807 // int32 left_bound = max_c(ceil(span_left-left_diff),max_c(absolute_left,left.x));
808 // int32 right_bound = min_c(min_c(absolute_right,right.x),floor(span_right-right_diff));
809 int32 left_bound = (int32)max_c(floor(span_left-left_diff),max_c(absolute_left,floor(left.x)))((floor(span_left-left_diff))>(((absolute_left)>(floor(
left.x))?(absolute_left):(floor(left.x))))?(floor(span_left-left_diff
)):(((absolute_left)>(floor(left.x))?(absolute_left):(floor
(left.x)))))
;
810 int32 right_bound = (int32)min_c(min_c(absolute_right,ceil(right.x)),ceil(span_right-right_diff))((((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
)))>(ceil(span_right-right_diff))?(ceil(span_right-right_diff
)):(((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
))))
;
811 for (int32 x=left_bound;x<=right_bound;x++) {
812 coverage = 0;
813 if ( (((left.y) + ((x-0.5)-left.x)*left_y_diff) < (y+0.5))
814 || (((right.y) + (right.x - (x+0.5))*right_y_diff) < (y+0.5)) ) {
815 // First calculate the subpixel coverages for the point x,y.
816 for (float sub_y = y - 0.51;sub_y <= y+0.51; sub_y += 1.0/(SUBPIXEL_AMOUNT-1)) {
817 for (float sub_x = x - 0.51;sub_x <= x+0.51; sub_x += 1.0/(SUBPIXEL_AMOUNT-1)) {
818 if ( (((left.y) + (sub_x - left.x)*left_y_diff) >= sub_y)
819 && (((right.y) + (right.x - sub_x)*right_y_diff) > sub_y) ) {
820 coverage++;
821 }
822 }
823 }
824 norm_color.bytes[3] = (uint8)(alpha*((float(coverage)) /
825 (SUBPIXEL_AMOUNT * SUBPIXEL_AMOUNT)));
826 SetPixel(x, int32(y), norm_color.word, sel, composite_func);
827 max_coverage = max_c(coverage, max_coverage)((coverage)>(max_coverage)?(coverage):(max_coverage));
828 }
829 else
830 SetPixel(x, int32(y), color, sel, composite_func);
831 }
832 }
833 y++;
834 span_left += left_diff;
835 span_right += right_diff;
836
837 }
838 }
839 else {
840 while (y <= bottom_y) {
841
842 if ((y<=absolute_bottom) && (y>=absolute_top)) {
843 // int32 left_bound = max_c(ceil(span_left+left_diff),max_c(absolute_left,left.x));
844 // int32 right_bound = min_c(min_c(absolute_right,right.x),floor(span_right+right_diff));
845 int32 left_bound = (int32)max_c(floor(span_left+left_diff),max_c(absolute_left,floor(left.x)))((floor(span_left+left_diff))>(((absolute_left)>(floor(
left.x))?(absolute_left):(floor(left.x))))?(floor(span_left+left_diff
)):(((absolute_left)>(floor(left.x))?(absolute_left):(floor
(left.x)))))
;
846 int32 right_bound = (int32)min_c(min_c(absolute_right,ceil(right.x)),ceil(span_right+right_diff))((((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
)))>(ceil(span_right+right_diff))?(ceil(span_right+right_diff
)):(((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
))))
;
847 for (int32 x=left_bound;x<=right_bound;x++) {
848 coverage = 0;
849 if ( (((top.y) + (top.x - (x-0.5))*left_y_diff) > (y-0.5))
850 || (((top.y) + ((x+0.5) - top.x )*right_y_diff) > (y-0.5)) ) {
851 // First calculate the subpixel coverages for the point x,y.
852 for (float sub_y = y - 0.51;sub_y <= y+0.51; sub_y += 1.0/(SUBPIXEL_AMOUNT-1)) {
853 for (float sub_x = x - 0.51;sub_x <= x+0.51; sub_x += 1.0/(SUBPIXEL_AMOUNT-1)) {
854 if ( (((top.y) + (top.x - sub_x)*left_y_diff) <= sub_y)
855 && (((top.y) + (sub_x - top.x )*right_y_diff) <= sub_y) ) {
856 coverage++;
857 }
858 }
859 }
860 norm_color.bytes[3] = (uint8)(alpha*((float(coverage)) /
861 (SUBPIXEL_AMOUNT * SUBPIXEL_AMOUNT)));
862 SetPixel(x, int32(y), norm_color.word, sel, composite_func);
863 max_coverage = max_c(coverage,max_coverage)((coverage)>(max_coverage)?(coverage):(max_coverage));
864 }
865 else
866 SetPixel(x, int32(y), color, sel, composite_func);
867 }
868 }
869 y++;
870 span_left += left_diff;
871 span_right += right_diff;
872
873 }
874
875 bottom_y = max_c(left.y,right.y)((left.y)>(right.y)?(left.y):(right.y));
876
877 if ((y>=left.y) && (left_diff <= 0)) {
878 left_diff = (bottom.x - left.x)/(bottom.y - left.y);
879 span_left = (y - left.y)*left_diff + left.x;
880 left_y_diff = (bottom.y - left.y)/(bottom.x - left.x);
881
882 while (y <= bottom_y) {
883 if ((y<=absolute_bottom) && (y>=absolute_top)) {
884 // int32 left_bound = max_c(ceil(span_left-left_diff),max_c(absolute_left,left.x));
885 // int32 right_bound = min_c(min_c(absolute_right,right.x),floor(span_right+right_diff));
886 int32 left_bound = (int32)max_c(floor(span_left-left_diff),max_c(absolute_left,floor(left.x)))((floor(span_left-left_diff))>(((absolute_left)>(floor(
left.x))?(absolute_left):(floor(left.x))))?(floor(span_left-left_diff
)):(((absolute_left)>(floor(left.x))?(absolute_left):(floor
(left.x)))))
;
887 int32 right_bound = (int32)min_c(min_c(absolute_right,ceil(right.x)),ceil(span_right+right_diff))((((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
)))>(ceil(span_right+right_diff))?(ceil(span_right+right_diff
)):(((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
))))
;
888 for (int32 x=left_bound;x<=right_bound;x++) {
889 coverage = 0;
890
891 // We can calculate y-coordinates of the boundaries at any given
892 // x-coordinate by using the y_diffs
893 if ( (((left.y) + ((x-0.5)-left.x)*left_y_diff) < (y+0.5))
894 || (((top.y) + ((x+0.5) - top.x )*right_y_diff) > (y-0.5)) ) {
895 // First calculate the subpixel coverages for the point x,y.
896 for (float sub_y = y - 0.51;sub_y <= y+0.51; sub_y += 1.0/(SUBPIXEL_AMOUNT-1)) {
897 for (float sub_x = x - 0.51;sub_x <= x+0.51; sub_x += 1.0/(SUBPIXEL_AMOUNT-1)) {
898 if ( (((left.y) + (sub_x - left.x)*left_y_diff) >= sub_y)
899 && (((top.y) + (sub_x - top.x )*right_y_diff) <= sub_y) ) {
900 coverage++;
901 }
902 }
903 }
904 norm_color.bytes[3] = (uint8)(alpha*((float(coverage)) /
905 (SUBPIXEL_AMOUNT * SUBPIXEL_AMOUNT)));
906 SetPixel(x, int32(y), norm_color.word, sel, composite_func);
907
908 max_coverage = max_c(coverage, max_coverage)((coverage)>(max_coverage)?(coverage):(max_coverage));
909 }
910 else
911 SetPixel(x, int32(y), color, sel, composite_func);
912 }
913 }
914 y++;
915 span_left += left_diff;
916 span_right += right_diff;
917
918 }
919 }
920 else if ((y>=right.y) && (right_diff >= 0)) {
921 right_diff = (bottom.x - right.x)/(bottom.y - right.y);
922 span_right = (y - right.y)*right_diff + right.x;
923 right_y_diff = (bottom.y - right.y)/(right.x - bottom.x);
924
925 while (y <= bottom_y) {
926
927 if ((y<=absolute_bottom) && (y>=absolute_top)) {
928 // int32 left_bound = max_c(ceil(span_left+left_diff),max_c(absolute_left,left.x));
929 // int32 right_bound = min_c(min_c(absolute_right,right.x),floor(span_right-right_diff));
930 int32 left_bound = (int32)max_c(floor(span_left+left_diff),max_c(absolute_left,floor(left.x)))((floor(span_left+left_diff))>(((absolute_left)>(floor(
left.x))?(absolute_left):(floor(left.x))))?(floor(span_left+left_diff
)):(((absolute_left)>(floor(left.x))?(absolute_left):(floor
(left.x)))))
;
931 int32 right_bound = (int32)min_c(min_c(absolute_right,ceil(right.x)),ceil(span_right-right_diff))((((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
)))>(ceil(span_right-right_diff))?(ceil(span_right-right_diff
)):(((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
))))
;
932 for (int32 x=left_bound;x<=right_bound;x++) {
933 coverage = 0;
934 if ( (((top.y) + (top.x - (x-0.5))*left_y_diff) > (y-0.5))
935 || (((right.y) + (right.x - (x+0.5))*right_y_diff) < (y+0.5)) ) {
936 // First calculate the subpixel coverages for the point x,y.
937 for (float sub_y = y - 0.51;sub_y <= y+0.51; sub_y += 1.0/(SUBPIXEL_AMOUNT-1)) {
938 for (float sub_x = x - 0.51;sub_x <= x+0.51; sub_x += 1.0/(SUBPIXEL_AMOUNT-1)) {
939 if ( (((top.y) + (top.x - sub_x)*left_y_diff) <= sub_y)
940 && (((right.y) + (right.x - sub_x)*right_y_diff) > sub_y) ) {
941 coverage++;
942 }
943 }
944 }
945 norm_color.bytes[3] = (uint8)(alpha*((float(coverage)) /
946 (SUBPIXEL_AMOUNT * SUBPIXEL_AMOUNT)));
947 SetPixel(x, int32(y), norm_color.word, sel, composite_func);
948 max_coverage = max_c(coverage, max_coverage)((coverage)>(max_coverage)?(coverage):(max_coverage));
949 }
950 else
951 SetPixel(x, int32(y), color, sel, composite_func);
952 }
953 }
954 y++;
955 span_left += left_diff;
956 span_right += right_diff;
957
958 }
959 }
960
961 bottom_y = ceil(bottom.y);
962 if ((y>=left.y) && (left_diff <= 0)) {
963 left_diff = (bottom.x - left.x)/(bottom.y - left.y);
964 span_left = (y - left.y)*left_diff + left.x;
965 left_y_diff = (bottom.y - left.y)/(bottom.x - left.x);
966 }
967 if ((y>=right.y) && (right_diff >= 0)) {
968 right_diff = (bottom.x - right.x)/(bottom.y - right.y);
969 span_right = (y - right.y)*right_diff + right.x;
970 right_y_diff = (bottom.y - right.y)/(right.x - bottom.x);
971 }
972
973 while (y <= bottom_y) {
974
975 if ((y<=absolute_bottom) && (y>=absolute_top)) {
976 // int32 left_bound = max_c(ceil(span_left-left_diff),max_c(absolute_left,left.x));
977 // int32 right_bound = min_c(min_c(absolute_right,right.x),floor(span_right-right_diff));
978 int32 left_bound = (int32)max_c(floor(span_left-left_diff),max_c(absolute_left,floor(left.x)))((floor(span_left-left_diff))>(((absolute_left)>(floor(
left.x))?(absolute_left):(floor(left.x))))?(floor(span_left-left_diff
)):(((absolute_left)>(floor(left.x))?(absolute_left):(floor
(left.x)))))
;
979 int32 right_bound = (int32)min_c(min_c(absolute_right,ceil(right.x)),ceil(span_right-right_diff))((((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
)))>(ceil(span_right-right_diff))?(ceil(span_right-right_diff
)):(((absolute_right)>(ceil(right.x))?(ceil(right.x)):(absolute_right
))))
;
980 for (int32 x=left_bound;x<=right_bound;x++) {
981 coverage = 0;
982 if ( (((left.y) + ((x-0.5)-left.x)*left_y_diff) < (y+0.5))
983 || (((right.y) + (right.x - (x+0.5))*right_y_diff) < (y+0.5)) ) {
984 // First calculate the subpixel coverages for the point x,y.
985 for (float sub_y = y - 0.51;sub_y <= y+0.51; sub_y += 1.0/(SUBPIXEL_AMOUNT-1)) {
986 for (float sub_x = x - 0.51;sub_x <= x+0.51; sub_x += 1.0/(SUBPIXEL_AMOUNT-1)) {
987 if ( (((left.y) + (sub_x - left.x)*left_y_diff) >= sub_y)
988 && (((right.y) + (right.x - sub_x)*right_y_diff) > sub_y) ) {
989 coverage++;
990 }
991 }
992 }
993 norm_color.bytes[3] = (uint8)(alpha*((float(coverage)) /
994 (SUBPIXEL_AMOUNT * SUBPIXEL_AMOUNT)));
995 SetPixel(x, int32(y), norm_color.word, sel, composite_func);
996 max_coverage = max_c(coverage, max_coverage)((coverage)>(max_coverage)?(coverage):(max_coverage));
997 }
998 else
999 SetPixel(x, int32(y), color, sel, composite_func);
1000 }
1001 }
1002 y++;
1003 span_left += left_diff;
1004 span_right += right_diff;
1005
1006 }
1007 }
1008 }
1009 return B_OK((int)0);
1010}
1011
1012
1013status_t
1014BitmapDrawer::FillRectangle(BPoint *corners, uint32 color, Selection *sel,
1015 uint32 (*composite_func)(uint32, uint32))
1016{
1017 // If the rectangle is aligned with the coordinate axis we do not need to
1018 // do much.
1019 if ((corners[0].x == corners[1].x) || (corners[0].y == corners[1].y)) {
1020 // Select minimum and maximum coordinates.
1021 int32 min_x = (int32)round(min_c(corners[0].x, corners[2].x)((corners[0].x)>(corners[2].x)?(corners[2].x):(corners[0].
x))
);
1022 int32 max_x = (int32)round(max_c(corners[0].x, corners[2].x)((corners[0].x)>(corners[2].x)?(corners[0].x):(corners[2].
x))
);
1023 int32 min_y = (int32)round(min_c(corners[0].y, corners[2].y)((corners[0].y)>(corners[2].y)?(corners[2].y):(corners[0].
y))
);
1024 int32 max_y = (int32)round(max_c(corners[0].y, corners[2].y)((corners[0].y)>(corners[2].y)?(corners[0].y):(corners[2].
y))
);
1025 // Then fill the rectangle.
1026 for (int32 y = min_y;y <= max_y;y++) {
1027 for (int32 x = min_x;x <= max_x;x++) {
1028 SetPixel(BPoint(x, y), color, sel, composite_func);
1029 }
1030 }
1031 }
1032 // If the rectanle is not rectilinear we must sort the points
1033 // and then fill the resulting rectangular polygon.
1034 else {
1035 // First we must sort the points.
1036 //
1037 // Top
1038 // Left
1039 // Right
1040 // Bottom
1041 BPoint left, right, top, bottom;
1042 left = right = top = bottom = corners[0];
1043 for (int32 i = 0;i < 4;i++) {
1044 if (corners[i].x < left.x)
1045 left = corners[i];
1046 if (corners[i].x > right.x)
1047 right = corners[i];
1048 if (corners[i].y < top.y)
1049 top = corners[i];
1050 if (corners[i].y > bottom.y)
1051 bottom = corners[i];
1052 }
1053
1054 float span_left;
1055 float span_right;
1056 float left_diff;
1057 float right_diff;
1058 left_diff = (left.x - top.x) / (left.y - top.y);
1059 right_diff = (right.x - top.x) / (right.y - top.y);
1060
1061 float y = ceil(top.y);
1062 float bottom_y = floor(bottom.y);
1063 span_left = (y - top.y) * left_diff + top.x;
1064 span_right = (y - top.y) * right_diff + top.x;
1065
1066 float absolute_left = 0;
1067 float absolute_right = bitmap_bounds.right;
1068 float absolute_top = 0;
1069 float absolute_bottom = bitmap_bounds.bottom;
1070
1071 bottom_y = min_c(left.y, right.y)((left.y)>(right.y)?(right.y):(left.y));
1072
1073 // This loop is split into three parts to avoid
1074 // having too many if-clauses inside the loop.
1075
1076 while (y <= bottom_y) {
1077
1078 if ((y<=absolute_bottom) && (y>=absolute_top)) {
1079 int32 left_bound = (int32)max_c(ceil(span_left),absolute_left)((ceil(span_left))>(absolute_left)?(ceil(span_left)):(absolute_left
))
;
1080 int32 right_bound = (int32)min_c(absolute_right,floor(span_right))((absolute_right)>(floor(span_right))?(floor(span_right)):
(absolute_right))
;
1081
1082 for (int32 x=left_bound;x<=right_bound;x++) {
1083 SetPixel(x, int32(y), color, sel, composite_func);
1084 }
1085 }
1086 y++;
1087 span_left += left_diff;
1088 span_right += right_diff;
1089
1090 }
1091
1092 bottom_y = max_c(left.y,right.y)((left.y)>(right.y)?(left.y):(right.y));
1093
1094 if ((y>=left.y) && (left_diff <= 0)) {
1095 left_diff = (bottom.x - left.x)/(bottom.y - left.y);
1096 span_left = (y - left.y)*left_diff + left.x;
1097 }
1098 if ((y>=right.y) && (right_diff >= 0)) {
1099 right_diff = (bottom.x - right.x)/(bottom.y - right.y);
1100 span_right = (y - right.y)*right_diff + right.x;
1101 }
1102
1103 while (y <= bottom_y) {
1104 if ((y<=absolute_bottom) && (y>=absolute_top)) {
1105 int32 left_bound = (int32)max_c(ceil(span_left),absolute_left)((ceil(span_left))>(absolute_left)?(ceil(span_left)):(absolute_left
))
;
1106 int32 right_bound = (int32)min_c(absolute_right,floor(span_right))((absolute_right)>(floor(span_right))?(floor(span_right)):
(absolute_right))
;
1107
1108 for (int32 x=left_bound;x<=right_bound;x++) {
1109 SetPixel(x, int32(y), color, sel, composite_func);
1110 }
1111 }
1112 y++;
1113 span_left += left_diff;
1114 span_right += right_diff;
1115
1116 }
1117
1118 bottom_y = floor(bottom.y);
1119 if ((y>=left.y) && (left_diff <= 0)) {
1120 left_diff = (bottom.x - left.x)/(bottom.y - left.y);
1121 span_left = (y - left.y)*left_diff + left.x;
1122 }
1123 if ((y>=right.y) && (right_diff >= 0)) {
1124 right_diff = (bottom.x - right.x)/(bottom.y - right.y);
1125 span_right = (y - right.y)*right_diff + right.x;
1126 }
1127
1128 while (y <= bottom_y) {
1129 if ((y<=absolute_bottom) && (y>=absolute_top)) {
1130 int32 left_bound = (int32)max_c(ceil(span_left),absolute_left)((ceil(span_left))>(absolute_left)?(ceil(span_left)):(absolute_left
))
;
1131 int32 right_bound = (int32)min_c(absolute_right,floor(span_right))((absolute_right)>(floor(span_right))?(floor(span_right)):
(absolute_right))
;
1132
1133 for (int32 x=left_bound;x<=right_bound;x++) {
1134 SetPixel(x, int32(y), color, sel, composite_func);
1135 }
1136 }
1137 y++;
1138 span_left += left_diff;
1139 span_right += right_diff;
1140
1141 }
1142 }
1143
1144 return B_OK((int)0);
1145}
1146
1147
1148status_t
1149BitmapDrawer::SetPixel(BPoint location, uint32 color, Selection* sel,
1150 uint32 (*composite_func)(uint32, uint32))
1151{
1152 if (sel == NULL__null || sel->ContainsPoint(location)) {
1153 if (bitmap_bounds.Contains(location)) {
1154 if (composite_func) {
1155 union {
1156 unsigned char bytes[4];
1157 uint32 word;
1158 } norm_color, target_color;
1159
1160 norm_color.word = color;
1161
1162 uint32 target = GetPixel(location);
1163 target_color.word = target;
1164
1165 *(bitmap_bits + (int32)location.x +
1166 (int32)location.y * bitmap_bpr) =
1167 (*composite_func)(
1168 target_color.word, norm_color.word
1169 );
1170 } else {
1171 *(bitmap_bits + (int32)location.x +
1172 (int32)location.y * bitmap_bpr) = color;
1173 }
1174
1175 return B_OK((int)0);
1176 }
1177 else
1178 return B_ERROR(-1);
1179 }
1180 else
1181 return B_ERROR(-1);
1182
1183}
1184
1185
1186status_t
1187BitmapDrawer::SetPixel(int32 x, int32 y, uint32 color, Selection* sel,
1188 uint32 (*composite_func)(uint32, uint32))
1189{
1190 return SetPixel(BPoint(x, y), color, sel, composite_func);
1191}
1192
1193
1194uint32
1195BitmapDrawer::GetPixel(BPoint location)
1196{
1197 if (bitmap_bounds.Contains(location)) {
1198 return *(bitmap_bits + (int32)location.x +
1199 (int32)location.y * bitmap_bpr);
1200 }
1201 else {
1202 union {
1203 unsigned char bytes[4];
1204 uint32 word;
1205 } color;
1206
1207 color.bytes[0] = 0xFF;
1208 color.bytes[1] = 0xFF;
1209 color.bytes[2] = 0xFF;
1210 color.bytes[3] = 0x00;
1211
1212 return color.word; // If out of bounds return transparent white.
1213 }
1214}
1215
1216
1217uint32
1218BitmapDrawer::GetPixel(int32 x, int32 y)
1219{
1220 return GetPixel(BPoint(x, y));
1221}
1222
1223
1224void
1225BitmapDrawer::SetMirroredPixels(BPoint center, uint32 x, uint32 y,
1226 uint32 color, Selection* sel, uint32 (*composite_func)(uint32, uint32))
1227{
1228 uint32 centerX = center.x;
1229 uint32 centerY = center.y;
1230
1231 SetPixel(centerX+x, centerY+y, color, sel, composite_func);
1232 SetPixel(centerX-x, centerY+y, color, sel, composite_func);
1233 SetPixel(centerX+x, centerY-y, color, sel, composite_func);
1234 SetPixel(centerX-x, centerY-y, color, sel, composite_func);
1235}
1236
1237
1238void
1239BitmapDrawer::FillColumn(BPoint center, uint32 x, uint32 miny, uint32 maxy,
1240 uint32 color, Selection* sel,
1241 uint32 (*composite_func)(uint32, uint32))
1242{
1243 uint32 centerX = center.x;
1244 uint32 centerY = center.y;
1245
1246 for (uint32 y = miny; y <= maxy; ++y) {
1247 SetPixel(centerX+x, centerY+y, color, sel, composite_func);
1248 SetPixel(centerX+x, centerY-y, color, sel, composite_func);
1249 if (x != 0) {
1250 SetPixel(centerX-x, centerY+y, color, sel, composite_func);
1251 if (y != 0)
1252 SetPixel(centerX-x, centerY-y, color, sel, composite_func);
1253 }
1254 }
1255}
1256
1257
1258void
1259BitmapDrawer::FillRow(BPoint center, uint32 minx, uint32 maxx,
1260 uint32 y, uint32 color, Selection* sel,
1261 uint32 (*composite_func)(uint32, uint32))
1262{
1263 uint32 centerX = center.x;
1264 uint32 centerY = center.y;
1265
1266 for (uint32 x = minx; x <= maxx; ++x) {
1267 SetPixel(centerX+x, centerY+y, color, sel, composite_func);
1268 SetPixel(centerX-x, centerY+y, color, sel, composite_func);
1269 if (y != 0) {
1270 SetPixel(centerX+x, centerY-y, color, sel, composite_func);
1271 if (x != 0)
1272 SetPixel(centerX-x, centerY-y, color, sel, composite_func);
1273 }
1274 }
1275}