File: | home/HaikuArchives/ArtPaint/artpaint/tools/BitmapDrawer.cpp |
Warning: | line 651, column 9 Value stored to 'bottom_y' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
20 | BitmapDrawer::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 | |
30 | status_t |
31 | BitmapDrawer::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 | |
162 | status_t |
163 | BitmapDrawer::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 | |
227 | status_t |
228 | BitmapDrawer::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 | |
241 | status_t |
242 | BitmapDrawer::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. |
343 | status_t |
344 | BitmapDrawer::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 | |
411 | status_t |
412 | BitmapDrawer::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 | |
488 | float |
489 | BitmapDrawer::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 | |
514 | float |
515 | BitmapDrawer::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 | |
540 | status_t |
541 | BitmapDrawer::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 | |
588 | status_t |
589 | BitmapDrawer::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 | |
1013 | status_t |
1014 | BitmapDrawer::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 | |
1148 | status_t |
1149 | BitmapDrawer::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 | |
1186 | status_t |
1187 | BitmapDrawer::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 | |
1194 | uint32 |
1195 | BitmapDrawer::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 | |
1217 | uint32 |
1218 | BitmapDrawer::GetPixel(int32 x, int32 y) |
1219 | { |
1220 | return GetPixel(BPoint(x, y)); |
1221 | } |
1222 | |
1223 | |
1224 | void |
1225 | BitmapDrawer::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 | |
1238 | void |
1239 | BitmapDrawer::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 | |
1258 | void |
1259 | BitmapDrawer::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 | } |