Skip to content

Commit

Permalink
AirBrushTool: attempting to get a smoother, better performing Airbrush
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
dsizzle committed Nov 4, 2023
1 parent addb47e commit b39e1b0
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 39 deletions.
66 changes: 40 additions & 26 deletions artpaint/tools/AirBrushTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -125,21 +125,24 @@ 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,
point.y + half_size);
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));
Expand All @@ -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);
Expand Down
18 changes: 10 additions & 8 deletions artpaint/tools/CoordinateReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand All @@ -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.
Expand Down Expand Up @@ -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(
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions artpaint/tools/CoordinateReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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);
};


Expand Down
2 changes: 1 addition & 1 deletion artpaint/tools/FreeLineTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit b39e1b0

Please sign in to comment.