Skip to content

Commit

Permalink
Tools: replace coordinate reading function with CoordinateReader class
Browse files Browse the repository at this point in the history
  • Loading branch information
dsizzle committed Oct 1, 2023
1 parent eeecadf commit 31949a9
Show file tree
Hide file tree
Showing 8 changed files with 203 additions and 381 deletions.
286 changes: 122 additions & 164 deletions artpaint/tools/AirBrushTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,24 +74,24 @@ AirBrushTool::UseTool(ImageView* view, uint32 buttons, BPoint point, BPoint)
while (LastUpdatedRect().IsValid())
snooze(50000);

coordinate_queue = new (std::nothrow) CoordinateQueue();
if (coordinate_queue == NULL)
return NULL;

image_view = view;
thread_id coordinate_reader
= spawn_thread(CoordinateReader, "read coordinates", B_NORMAL_PRIORITY, this);
resume_thread(coordinate_reader);
CoordinateReader* coordinate_reader
= new (std::nothrow) CoordinateReader(view, NO_INTERPOLATION, false);
if (coordinate_reader == NULL)
return NULL;
reading_coordinates = true;

BPoint prev_point;
BBitmap* bitmap = view->ReturnImage()->ReturnActiveBitmap();
BBitmap* srcBuffer = new (std::nothrow) BBitmap(bitmap);
if (srcBuffer == NULL)
if (srcBuffer == NULL) {
delete coordinate_reader;
return NULL;
}
BBitmap* tmpBuffer = new (std::nothrow) BBitmap(bitmap);
if (tmpBuffer == NULL) {
delete srcBuffer;
delete coordinate_reader;
return NULL;
}

Expand Down Expand Up @@ -125,148 +125,142 @@ AirBrushTool::UseTool(ImageView* view, uint32 buttons, BPoint point, BPoint)
prev_point = point - BPoint(1, 1);
SetLastUpdatedRect(BRect(point, point));
// while (buttons) {
while (((status_of_read = coordinate_queue->Get(point)) == B_OK)
|| (reading_coordinates == true)) {
if ((status_of_read == 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();
int32 left = (int32)rc.left;
int32 top = (int32)rc.top;

for (int32 y = 0; y <= height; y++) {
int32 y_sqr = (int32)((point.y - rc.top - y) * (point.y - rc.top - y));
for (int32 x = 0; x <= width; x++) {
int32 dx = (int32)(point.x - rc.left - x);
float distance = sqrt_table[dx * dx + y_sqr];
if ((distance <= half_size)
&& (selection->IsEmpty()
|| selection->ContainsPoint(left + x, top + y))) {
float change = (half_size - distance) / half_size;
change *= ((float)fToolSettings.pressure) / 100.0;

// 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);
}
while (coordinate_reader->GetPoint(point) == 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();
int32 left = (int32)rc.left;
int32 top = (int32)rc.top;

for (int32 y = 0; y <= height; y++) {
int32 y_sqr = (int32)((point.y - rc.top - y) * (point.y - rc.top - y));
for (int32 x = 0; x <= width; x++) {
int32 dx = (int32)(point.x - rc.left - x);
float distance = sqrt_table[dx * dx + y_sqr];
if ((distance <= half_size)
&& (selection->IsEmpty()
|| selection->ContainsPoint(left + x, top + y))) {
float change = (half_size - distance) / half_size;
change *= ((float)fToolSettings.pressure) / 100.0;

// 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);
}
}
}
}
}

imageUpdater->AddRect(rc);
SetLastUpdatedRect(LastUpdatedRect() | rc);
BitmapUtilities::CompositeBitmapOnSource(bitmap, srcBuffer, tmpBuffer, rc);
imageUpdater->AddRect(rc);
SetLastUpdatedRect(LastUpdatedRect() | rc);
BitmapUtilities::CompositeBitmapOnSource(bitmap, srcBuffer, tmpBuffer, rc);

snooze(20 * 1000);
}
snooze(20 * 1000);
}
} else if (fToolSettings.mode == HS_SPRAY_MODE) { // Do the spray
RandomNumberGenerator* generator = new RandomNumberGenerator(0, 10000);
prev_point = point;

while (((status_of_read = coordinate_queue->Get(point)) == B_OK)
|| (reading_coordinates == true)) {
if ((status_of_read == B_OK)) {
int32 flow = fToolSettings.pressure + 1;
float width = fToolSettings.size;
float angle;
float opacity = 0.4;

BRect rc(point, point);

if (point == prev_point) {
for (int32 i = 0; i < flow; i++) {
float x = generator->UniformDistribution(0, width * .5);
float y = generator->UniformDistribution(
0, sqrt((width * .5) * (width * .5) - x * x));

angle = generator->UniformDistribution(0, 1.0) * 2 * M_PI;
float old_x = x;
x = cos(angle) * x - sin(angle) * y;
y = sin(angle) * old_x + cos(angle) * y;
BPoint new_point = point + BPoint(x, y);
new_point.x = round(new_point.x);
new_point.y = round(new_point.y);
rc = rc | BRect(new_point, new_point);

if (selection->IsEmpty() || selection->ContainsPoint(new_point)) {
drawer->SetPixel(new_point,
mix_2_pixels_fixed(target_color, drawer->GetPixel(new_point),
(uint32)(32768 * opacity)),
selection, NULL);
}
while (coordinate_reader->GetPoint(point) == B_OK) {
int32 flow = fToolSettings.pressure + 1;
float width = fToolSettings.size;
float angle;
float opacity = 0.4;

BRect rc(point, point);

if (point == prev_point) {
for (int32 i = 0; i < flow; i++) {
float x = generator->UniformDistribution(0, width * .5);
float y = generator->UniformDistribution(
0, sqrt((width * .5) * (width * .5) - x * x));

angle = generator->UniformDistribution(0, 1.0) * 2 * M_PI;
float old_x = x;
x = cos(angle) * x - sin(angle) * y;
y = sin(angle) * old_x + cos(angle) * y;
BPoint new_point = point + BPoint(x, y);
new_point.x = round(new_point.x);
new_point.y = round(new_point.y);
rc = rc | BRect(new_point, new_point);

if (selection->IsEmpty() || selection->ContainsPoint(new_point)) {
drawer->SetPixel(new_point,
mix_2_pixels_fixed(target_color, drawer->GetPixel(new_point),
(uint32)(32768 * opacity)),
selection, NULL);
}
} else {
BPoint center;
for (int32 i = 0; i < flow; i++) {
float x = generator->UniformDistribution(0, width * .5);
float y = generator->UniformDistribution(
0, sqrt((width * .5) * (width * .5) - x * x));

// Select center randomly from the line between prev_point and point.
// This is done by doing a linear interpolation between the
// two points and rounding the result to nearest integer.
float a = generator->UniformDistribution(0, 1.0);
center.x = round(a * prev_point.x + (1.0 - a) * point.x);
center.y = round(a * prev_point.y + (1.0 - a) * point.y);

angle = generator->UniformDistribution(0, 1.0) * 2 * M_PI;
float old_x = x;
x = cos(angle) * x - sin(angle) * y;
y = sin(angle) * old_x + cos(angle) * y;
BPoint new_point = center + BPoint(x, y);
new_point.x = round(new_point.x);
new_point.y = round(new_point.y);
rc = rc | BRect(new_point, new_point);

if (selection->IsEmpty() || selection->ContainsPoint(new_point)) {
drawer->SetPixel(new_point,
mix_2_pixels_fixed(target_color, drawer->GetPixel(new_point),
(uint32)(32768 * opacity)),
selection, NULL);
}
}
} else {
BPoint center;
for (int32 i = 0; i < flow; i++) {
float x = generator->UniformDistribution(0, width * .5);
float y = generator->UniformDistribution(
0, sqrt((width * .5) * (width * .5) - x * x));

// Select center randomly from the line between prev_point and point.
// This is done by doing a linear interpolation between the
// two points and rounding the result to nearest integer.
float a = generator->UniformDistribution(0, 1.0);
center.x = round(a * prev_point.x + (1.0 - a) * point.x);
center.y = round(a * prev_point.y + (1.0 - a) * point.y);

angle = generator->UniformDistribution(0, 1.0) * 2 * M_PI;
float old_x = x;
x = cos(angle) * x - sin(angle) * y;
y = sin(angle) * old_x + cos(angle) * y;
BPoint new_point = center + BPoint(x, y);
new_point.x = round(new_point.x);
new_point.y = round(new_point.y);
rc = rc | BRect(new_point, new_point);

if (selection->IsEmpty() || selection->ContainsPoint(new_point)) {
drawer->SetPixel(new_point,
mix_2_pixels_fixed(target_color, drawer->GetPixel(new_point),
(uint32)(32768 * opacity)),
selection, NULL);
}
}
prev_point = point;

imageUpdater->AddRect(rc);
SetLastUpdatedRect(LastUpdatedRect() | rc);
BitmapUtilities::CompositeBitmapOnSource(bitmap, srcBuffer, tmpBuffer, rc);
}
prev_point = point;

imageUpdater->AddRect(rc);
SetLastUpdatedRect(LastUpdatedRect() | rc);
BitmapUtilities::CompositeBitmapOnSource(bitmap, srcBuffer, tmpBuffer, rc);
}

delete generator;
}

imageUpdater->ForceUpdate();
delete imageUpdater;
delete coordinate_queue;
delete coordinate_reader;

delete drawer;
delete srcBuffer;
Expand Down Expand Up @@ -304,42 +298,6 @@ AirBrushTool::HelpString(bool isInUse) const
}


int32
AirBrushTool::CoordinateReader(void* data)
{
AirBrushTool* this_pointer = (AirBrushTool*)data;
return this_pointer->read_coordinates();
}


int32
AirBrushTool::read_coordinates()
{
reading_coordinates = true;
uint32 buttons;
BPoint point, prev_point;
BPoint view_point;
image_view->Window()->Lock();
image_view->getCoords(&point, &buttons, &view_point);
image_view->MovePenTo(view_point);
image_view->Window()->Unlock();
prev_point = point + BPoint(1, 1);

while (buttons) {
image_view->Window()->Lock();
if (point != prev_point || fToolSettings.mode == HS_SPRAY_MODE) {
coordinate_queue->Put(point);
prev_point = point;
}
image_view->getCoords(&point, &buttons, &view_point);
image_view->Window()->Unlock();
snooze(20 * 1000);
}

reading_coordinates = false;
return B_OK;
}

// #pragma mark -- AirBrushToolConfigView


Expand Down
3 changes: 0 additions & 3 deletions artpaint/tools/AirBrushTool.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@ class AirBrushTool : public DrawingTool {
const char* HelpString(bool isInUse) const;

private:
int32 read_coordinates();
static int32 CoordinateReader(void*);

bool reading_coordinates;

ImageView* image_view;
Expand Down
Loading

0 comments on commit 31949a9

Please sign in to comment.