From b39e1b0a8c1d28ec85f540b918e89d0f68cc79ae Mon Sep 17 00:00:00 2001 From: Dale Cieslak Date: Fri, 3 Nov 2023 17:51:41 -0700 Subject: [PATCH] AirBrushTool: attempting to get a smoother, better performing Airbrush - only calculate 1/4 of the brush and draw 4 pixels at once - use LINEAR_INTERPOLATION in the CoordinateReader to get a smoother line - adjusted linear interpolation to only get 1/10th of the coordinates - remove snooze - changed FreeLineTool to NO_INTERPOLATION; it doesn't need interpolation --- artpaint/tools/AirBrushTool.cpp | 66 +++++++++++++++++------------ artpaint/tools/CoordinateReader.cpp | 18 ++++---- artpaint/tools/CoordinateReader.h | 8 ++-- artpaint/tools/FreeLineTool.cpp | 2 +- 4 files changed, 55 insertions(+), 39 deletions(-) diff --git a/artpaint/tools/AirBrushTool.cpp b/artpaint/tools/AirBrushTool.cpp index e083c815..6b8c267c 100644 --- a/artpaint/tools/AirBrushTool.cpp +++ b/artpaint/tools/AirBrushTool.cpp @@ -76,7 +76,7 @@ AirBrushTool::UseTool(ImageView* view, uint32 buttons, BPoint point, BPoint) image_view = view; CoordinateReader* coordinate_reader - = new (std::nothrow) CoordinateReader(view, NO_INTERPOLATION, false); + = new (std::nothrow) CoordinateReader(view, LINEAR_INTERPOLATION, false, false, 0); if (coordinate_reader == NULL) return NULL; reading_coordinates = true; @@ -125,9 +125,10 @@ AirBrushTool::UseTool(ImageView* view, uint32 buttons, BPoint point, BPoint) prev_point = point - BPoint(1, 1); SetLastUpdatedRect(BRect(point, point)); // while (buttons) { - while (coordinate_reader->GetPoint(point) == B_OK) { + int32 step_factor = max_c(1.0, fToolSettings.size / 5); + while (coordinate_reader->GetPoint(point, step_factor) == B_OK) { the_script->AddPoint(point); - + float half_size = fToolSettings.size / 2; // we should only consider points that are inside this rectangle rc = BRect(point.x - half_size, point.y - half_size, point.x + half_size, @@ -135,11 +136,13 @@ AirBrushTool::UseTool(ImageView* view, uint32 buttons, BPoint point, BPoint) rc = rc & bounds; rc = rc & selection->GetBoundingRect(); - if (rc.IsValid() == true) { - int32 height = rc.IntegerHeight(); - int32 width = rc.IntegerWidth(); + if (rc.IsValid() == true && point != prev_point) { + int32 height = rc.IntegerHeight() / 2; + int32 width = rc.IntegerWidth() / 2; int32 left = (int32)rc.left; int32 top = (int32)rc.top; + int32 right = (int32)rc.right; + int32 bottom = (int32)rc.bottom; for (int32 y = 0; y <= height; y++) { int32 y_sqr = (int32)((point.y - rc.top - y) * (point.y - rc.top - y)); @@ -151,37 +154,48 @@ AirBrushTool::UseTool(ImageView* view, uint32 buttons, BPoint point, BPoint) || selection->ContainsPoint(left + x, top + y))) { float change = (half_size - distance) / half_size; change *= ((float)fToolSettings.pressure) / 100.0; + change *= 32768; // This is experimental for doing a real transparency // Seems to work quite well - union { - uint8 bytes[4]; - uint32 word; - } color; - color.word = drawer->GetPixel(left + x, top + y); - if (color.bytes[3] != 0x00) { - drawer->SetPixel(left + x, top + y, - mix_2_pixels_fixed( - target_color, color.word, (uint32)(32768 * change)), - selection, NULL); - } else { - color.word = target_color; - color.bytes[3] = 0x00; - drawer->SetPixel(left + x, top + y, - mix_2_pixels_fixed( - target_color, color.word, (uint32)(32768 * change)), - selection, NULL); - } + union color_conversion color1, color2, color3, color4; + color1.word = drawer->GetPixel(left + x, top + y); + color2.word = drawer->GetPixel(right - x, top + y); + color3.word = drawer->GetPixel(left + x, bottom - y); + color4.word = drawer->GetPixel(right - x, bottom - y); + if (color1.bytes[3] == 0x00) + color1.word = clear_color.word; + if (color2.bytes[3] == 0x00) + color2.word = clear_color.word; + if (color3.bytes[3] == 0x00) + color3.word = clear_color.word; + if (color4.bytes[3] == 0x00) + color4.word = clear_color.word; + drawer->SetPixel(left + x, top + y, + mix_2_pixels_fixed( + target_color, color1.word, (uint32)(change)), + selection, NULL); + drawer->SetPixel(right - x, top + y, + mix_2_pixels_fixed( + target_color, color2.word, (uint32)(change)), + selection, NULL); + drawer->SetPixel(left + x, bottom - y, + mix_2_pixels_fixed( + target_color, color3.word, (uint32)(change)), + selection, NULL); + drawer->SetPixel(right - x, bottom - y, + mix_2_pixels_fixed( + target_color, color4.word, (uint32)(change)), + selection, NULL); } } } } + prev_point = point; imageUpdater->AddRect(rc); SetLastUpdatedRect(LastUpdatedRect() | rc); BitmapUtilities::CompositeBitmapOnSource(bitmap, srcBuffer, tmpBuffer, rc); - - snooze(20 * 1000); } } else if (fToolSettings.mode == HS_SPRAY_MODE) { // Do the spray RandomNumberGenerator* generator = new RandomNumberGenerator(0, 10000); diff --git a/artpaint/tools/CoordinateReader.cpp b/artpaint/tools/CoordinateReader.cpp index 72787e0d..b89a621a 100644 --- a/artpaint/tools/CoordinateReader.cpp +++ b/artpaint/tools/CoordinateReader.cpp @@ -57,15 +57,15 @@ CoordinateReader::~CoordinateReader() status_t -CoordinateReader::GetPoint(BPoint& point) +CoordinateReader::GetPoint(BPoint& point, int32 step_factor) { switch (style) { case NO_INTERPOLATION: return NextPointNoInterpolation(point); case LINEAR_INTERPOLATION: - return NextPointLinearInterpolation(point); + return NextPointLinearInterpolation(point, step_factor); case CARDINAL_SPLINE_INTERPOLATION: - return NextPointCardinalSplineInterpolation(point); + return NextPointCardinalSplineInterpolation(point, step_factor); default: return B_ERROR; } @@ -128,8 +128,9 @@ status_t CoordinateReader::NextPointNoInterpolation(BPoint& point) { while ((point_queue_length == 0) && (continue_reading)) - snooze(50 * 1000); - + //snooze(10 * 1000); + snooze((bigtime_t)reader_delay); + if (point_queue_head != NULL) { EnterCS(); queue_entry* entry = point_queue_head; @@ -149,7 +150,7 @@ CoordinateReader::NextPointNoInterpolation(BPoint& point) status_t -CoordinateReader::NextPointLinearInterpolation(BPoint& point) +CoordinateReader::NextPointLinearInterpolation(BPoint& point, int32 step_factor) { if (!interpolation_started) { // Take the two first interpolation points. @@ -210,7 +211,7 @@ CoordinateReader::NextPointLinearInterpolation(BPoint& point) int32 new_x; do { - interpolation_parameter += interpolation_step; + interpolation_parameter += interpolation_step * step_factor; new_x = (int32)round( p0.x * (1.0 - interpolation_parameter) + p1.x * interpolation_parameter); new_y = (int32)round( @@ -232,7 +233,7 @@ CoordinateReader::NextPointLinearInterpolation(BPoint& point) status_t -CoordinateReader::NextPointCardinalSplineInterpolation(BPoint& point) +CoordinateReader::NextPointCardinalSplineInterpolation(BPoint& point, int32 step_factor) { if (!interpolation_started) { // Take the four first interpolation points. @@ -319,6 +320,7 @@ CoordinateReader::NextPointCardinalSplineInterpolation(BPoint& point) float u = interpolation_parameter; + interpolation_step *= step_factor; do { u = min_c(u + interpolation_step, 1); new_x diff --git a/artpaint/tools/CoordinateReader.h b/artpaint/tools/CoordinateReader.h index f78dba97..7fcb91bc 100644 --- a/artpaint/tools/CoordinateReader.h +++ b/artpaint/tools/CoordinateReader.h @@ -72,9 +72,9 @@ class CoordinateReader { static int32 thread_entry(void*); int32 reader_function(); - status_t NextPointNoInterpolation(BPoint&); - status_t NextPointLinearInterpolation(BPoint&); - status_t NextPointCardinalSplineInterpolation(BPoint&); + status_t NextPointNoInterpolation(BPoint& point); + status_t NextPointLinearInterpolation(BPoint& point, int32 step_factor); + status_t NextPointCardinalSplineInterpolation(BPoint& point, int32 step_factor); inline float round(float); @@ -83,7 +83,7 @@ class CoordinateReader { bool trace_path = FALSE, bool duplicates = FALSE, double delay = 10000.0); ~CoordinateReader(); - status_t GetPoint(BPoint&); + status_t GetPoint(BPoint& point, int32 step_factor = 1); }; diff --git a/artpaint/tools/FreeLineTool.cpp b/artpaint/tools/FreeLineTool.cpp index 75694ad4..ef6e5e0e 100644 --- a/artpaint/tools/FreeLineTool.cpp +++ b/artpaint/tools/FreeLineTool.cpp @@ -66,7 +66,7 @@ FreeLineTool::UseTool(ImageView* view, uint32 buttons, BPoint point, BPoint) image_view = view; CoordinateReader* coordinate_reader - = new (std::nothrow) CoordinateReader(view, LINEAR_INTERPOLATION, false); + = new (std::nothrow) CoordinateReader(view, NO_INTERPOLATION, false); if (coordinate_reader == NULL) return NULL;