Commit 339deed1 authored by Alexia Death's avatar Alexia Death

app: Clean up smooth so it would be acceptable for master

parent 082aa272
......@@ -398,7 +398,7 @@ gimp_brush_core_post_paint (GimpPaintCore *paint_core,
guint32 time)
{
GimpBrushCore *core = GIMP_BRUSH_CORE (paint_core);
if (paint_state == GIMP_PAINT_STATE_MOTION)
{
core->brush = core->main_brush;
......@@ -520,9 +520,9 @@ gimp_brush_core_interpolate (GimpPaintCore *paint_core,
gimp_paint_core_get_last_coords (paint_core, &last_coords);
gimp_paint_core_get_current_coords (paint_core, &current_coords);
if (paint_core->smoothing_history) {
current_coords = gimp_paint_options_get_smoothed_coords(paint_options, &current_coords, paint_core->smoothing_history);
if (paint_core->stroke_buffer) {
current_coords = gimp_paint_core_get_smoothed_coords(paint_core, paint_options, &current_coords);
gimp_paint_core_set_current_coords (paint_core, &current_coords);
}
......
......@@ -152,7 +152,6 @@ gimp_ink_paint (GimpPaintCore *paint_core,
case GIMP_PAINT_STATE_INIT:
gimp_paint_core_get_last_coords (paint_core, &last_coords);
ink->queue = gimp_circular_queue_new(sizeof(GimpCoords), paint_options->smoothing_options->smoothing_history);
if (coords->x == last_coords.x &&
coords->y == last_coords.y)
......@@ -187,8 +186,6 @@ gimp_ink_paint (GimpPaintCore *paint_core,
break;
case GIMP_PAINT_STATE_FINISH:
gimp_circular_queue_free(ink->queue);
ink->queue = NULL;
break;
}
}
......@@ -260,8 +257,8 @@ gimp_ink_motion (GimpPaintCore *paint_core,
GimpCoords modified_coords;
image = gimp_item_get_image (GIMP_ITEM (drawable));
modified_coords = gimp_paint_options_get_smoothed_coords(paint_options, coords, ink->queue);
modified_coords = gimp_paint_core_get_smoothed_coords(paint_core, paint_options, coords);
if (! ink->last_blob)
{
......
......@@ -42,7 +42,6 @@ struct _GimpInk
GimpBlob *cur_blob; /* current blob */
GimpBlob *last_blob; /* blob for last cursor position */
GimpCircularQueue *queue;
};
struct _GimpInkClass
......
......@@ -49,6 +49,7 @@
#include "gimp-intl.h"
#define STROKE_BUFFER_INIT_SIZE 2000
enum
{
......@@ -351,8 +352,16 @@ gimp_paint_core_start (GimpPaintCore *core,
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
item = GIMP_ITEM (drawable);
core->smoothing_history = gimp_circular_queue_new (sizeof(GimpCoords), paint_options->smoothing_options->smoothing_history);
if (core->stroke_buffer != NULL)
{
g_array_free(core->stroke_buffer, TRUE);
core->stroke_buffer = NULL;
}
core->stroke_buffer = g_array_sized_new (TRUE, TRUE,
sizeof(GimpCoords),
STROKE_BUFFER_INIT_SIZE);
core->cur_coords = *coords;
......@@ -420,10 +429,10 @@ gimp_paint_core_finish (GimpPaintCore *core,
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
if (core->smoothing_history) {
gimp_circular_queue_free (core->smoothing_history);
core->smoothing_history = NULL;
if (core->stroke_buffer) {
g_array_free (core->stroke_buffer, TRUE);
core->stroke_buffer = NULL;
}
image = gimp_item_get_image (GIMP_ITEM (drawable));
......@@ -1240,3 +1249,60 @@ gimp_paint_core_validate_canvas_tiles (GimpPaintCore *core,
}
}
}
GimpCoords gimp_paint_core_get_smoothed_coords (GimpPaintCore *core,
GimpPaintOptions *paint_options,
const GimpCoords *original_coords)
{
GimpSmoothingOptions *smoothing_options = paint_options->smoothing_options;
GArray *history = core->stroke_buffer;
if (smoothing_options->use_smoothing && smoothing_options->smoothing_quality > 0)
{
int i;
guint length;
gint min_index;
GimpCoords result = *original_coords;
gdouble gaussian_weight = 0.0;
gdouble gaussian_weight2 = SQR (smoothing_options->smoothing_factor);
gdouble velocity_sum = 0.0;
gdouble scale_sum = 0.0;
result.x = result.y = 0.0;
g_array_append_val (history, *original_coords);
length = MIN(smoothing_options->smoothing_quality, history->len);
min_index = history->len - length;
if (gaussian_weight2 != 0.0)
gaussian_weight = 1 / (sqrt (2 * G_PI) * smoothing_options->smoothing_factor);
for (i = history->len - 1; i >= min_index; i--) {
gdouble rate = 0.0;
GimpCoords* next_coords = &g_array_index (history,
GimpCoords, i);
if (gaussian_weight2 != 0.0)
{
/* We use gaussian function with velocity as a window function */
velocity_sum += next_coords->velocity * 100;
rate = gaussian_weight * exp (-velocity_sum*velocity_sum / (2 * gaussian_weight2));
}
scale_sum += rate;
result.x += rate * next_coords->x;
result.y += rate * next_coords->y;
}
if (scale_sum != 0.0)
{
result.x /= scale_sum;
result.y /= scale_sum;
}
return result;
}
return *original_coords;
}
......@@ -64,8 +64,8 @@ struct _GimpPaintCore
TempBuf *orig_buf; /* the unmodified drawable pixels */
TempBuf *orig_proj_buf; /* the unmodified projection pixels */
TempBuf *canvas_buf; /* the buffer to paint pixels to */
GimpCircularQueue *smoothing_history;
GArray *stroke_buffer;
};
struct _GimpPaintCoreClass
......@@ -204,5 +204,9 @@ void gimp_paint_core_validate_canvas_tiles (GimpPaintCore *core,
gint w,
gint h);
GimpCoords gimp_paint_core_get_smoothed_coords (GimpPaintCore *core,
GimpPaintOptions *paint_options,
const GimpCoords *original_coords);
#endif /* __GIMP_PAINT_CORE_H__ */
......@@ -36,55 +36,6 @@
#include "gimp-intl.h"
GimpCircularQueue* gimp_circular_queue_new(guint element_size, guint queue_size)
{
GimpCircularQueue* queue = g_new0(GimpCircularQueue, 1);
queue->data = g_malloc0(element_size * queue_size);
if (queue->data) {
queue->element_size = element_size;
queue->queue_size = queue_size;
}
queue->start = 0;
queue->end = 0;
return queue;
}
void gimp_circular_queue_free(GimpCircularQueue* queue)
{
if (queue) {
if (queue->data)
g_free(queue->data);
g_free(queue);
}
}
void gimp_circular_queue_enqueue_data(GimpCircularQueue* queue, gpointer data)
{
guint index = queue->end % queue->queue_size;
if (index > queue->start && index == queue->start % queue->queue_size)
queue->start ++;
index *= queue->element_size;
g_memmove((guchar*)queue->data + index, data, queue->element_size);
queue->end ++;
}
gpointer gimp_circular_queue_get_nth_offset(GimpCircularQueue* queue, guint index)
{
index = (queue->start + index) % queue->queue_size;
index *= queue->element_size;
return (guchar*)queue->data + index;
}
gpointer gimp_circular_queue_get_last_offset(GimpCircularQueue* queue)
{
gint index = (queue->end - 1) % queue->queue_size;
index *= queue->element_size;
return (guchar*)queue->data + index;
}
#define DEFAULT_BRUSH_SIZE 20.0
#define DEFAULT_BRUSH_ASPECT_RATIO 1.0
#define DEFAULT_BRUSH_ANGLE 0.0
......@@ -110,7 +61,7 @@ gpointer gimp_circular_queue_get_last_offset(GimpCircularQueue* queue)
#define DYNAMIC_MAX_VALUE 1.0
#define DYNAMIC_MIN_VALUE 0.0
#define DEFAULT_SMOOTHING_HISTORY 20
#define DEFAULT_SMOOTHING_QUALITY 20
#define DEFAULT_SMOOTHING_FACTOR 50
enum
......@@ -148,7 +99,7 @@ enum
PROP_GRADIENT_VIEW_SIZE,
PROP_USE_SMOOTHING,
PROP_SMOOTHING_HISTORY,
PROP_SMOOTHING_QUALITY,
PROP_SMOOTHING_FACTOR
};
......@@ -298,20 +249,22 @@ gimp_paint_options_class_init (GimpPaintOptionsClass *klass)
GIMP_VIEW_SIZE_LARGE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_SMOOTHING_HISTORY,
"smoothing-history", NULL,
1,
100,
DEFAULT_SMOOTHING_HISTORY,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_USE_SMOOTHING,
"use-smoothing", NULL,
FALSE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_SMOOTHING_QUALITY,
"smoothing-quality", NULL,
1,
100,
DEFAULT_SMOOTHING_QUALITY,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_SMOOTHING_FACTOR,
"smoothing-factor", NULL,
0.0, 1000.0, DEFAULT_SMOOTHING_FACTOR,
3.0, 1000.0, DEFAULT_SMOOTHING_FACTOR, /* Max velocity is set at 3.
* Allowing for smoothing factor to be
* less than velcoty results in numeric
* instablility */
GIMP_PARAM_STATIC_STRINGS);
}
......@@ -459,8 +412,8 @@ gimp_paint_options_set_property (GObject *object,
smoothing_options->use_smoothing = g_value_get_boolean (value);
break;
case PROP_SMOOTHING_HISTORY:
smoothing_options->smoothing_history = g_value_get_int (value);
case PROP_SMOOTHING_QUALITY:
smoothing_options->smoothing_quality = g_value_get_int (value);
break;
case PROP_SMOOTHING_FACTOR:
......@@ -574,13 +527,13 @@ gimp_paint_options_get_property (GObject *object,
case PROP_GRADIENT_VIEW_SIZE:
g_value_set_int (value, options->gradient_view_size);
break;
case PROP_USE_SMOOTHING:
g_value_set_boolean(value, smoothing_options->use_smoothing);
break;
case PROP_SMOOTHING_HISTORY:
g_value_set_int (value, smoothing_options->smoothing_history);
case PROP_SMOOTHING_QUALITY:
g_value_set_int (value, smoothing_options->smoothing_quality);
break;
case PROP_SMOOTHING_FACTOR:
......@@ -749,65 +702,3 @@ gimp_paint_options_get_brush_mode (GimpPaintOptions *paint_options)
return GIMP_BRUSH_SOFT;
}
GimpCoords gimp_paint_options_get_smoothed_coords (GimpPaintOptions *paint_options,
const GimpCoords *original_coords,
GimpCircularQueue *history)
{
gdouble PI = 4 * atan(1);
GimpSmoothingOptions *smoothing_options = paint_options->smoothing_options;
if (smoothing_options->use_smoothing && smoothing_options->smoothing_history > 0) {
int i;
GimpCoords result = *original_coords;
guint length;
gdouble gaussian_weight = 0.0;
gdouble gaussian_weight2 = SQR (smoothing_options->smoothing_factor);
gdouble velocity_sum = 0.0;
gint min_index;
gdouble scale_sum = 0.0;
result.x = result.y = 0.0;
gimp_circular_queue_enqueue(history, *original_coords);
length = gimp_circular_queue_length(history);
min_index = length - MIN(length, smoothing_options->smoothing_history);
if (gaussian_weight2 != 0.0)
gaussian_weight = 1 / (sqrt (2 * PI) * smoothing_options->smoothing_factor);
// g_print("IN:%f-%f\n", original_coords->x, original_coords->y);
for (i = (int)(length - 1); i >= min_index; i--) {
gdouble rate = 0;
GimpCoords* next_coords = &gimp_circular_queue_index(history, GimpCoords, i);
// g_print("%d: %f-%f\n", i, next_coords->x, next_coords->y);
if (gaussian_weight2 != 0)
{
/* We use gaussian function with velocity as a window function */
velocity_sum += next_coords->velocity * 100;
rate = gaussian_weight * exp (-velocity_sum*velocity_sum / (2 * gaussian_weight2));
/* If i == 0 && rate == 0.0, resulting value becomes zero.
* To avoid this, we treat this as a special case.
*/
if (i == 0 && rate == 0.0)
rate = 1.0;
}
else
{
rate = (i == 0) ? 1.0 : 0.0;
}
scale_sum += rate;
result.x += rate * next_coords->x;
result.y += rate * next_coords->y;
}
if (scale_sum != 0.0)
{
result.x /= scale_sum;
result.y /= scale_sum;
}
// g_print("OUT:%f-%f\n", result.x, result.y);
return result;
}
return *original_coords;
}
......@@ -29,25 +29,6 @@
GIMP_CONTEXT_BRUSH_MASK | \
GIMP_CONTEXT_DYNAMICS_MASK
typedef struct _GimpCircularQueue GimpCircularQueue;
struct _GimpCircularQueue
{
guint element_size;
guint queue_size;
guint start;
guint end;
gpointer data;
};
GimpCircularQueue* gimp_circular_queue_new(guint element_size, guint queue_size);
void gimp_circular_queue_free(GimpCircularQueue* queue);
void gimp_circular_queue_enqueue_data(GimpCircularQueue* queue, gpointer data);
gpointer gimp_circular_queue_get_nth_offset(GimpCircularQueue* queue, guint index);
gpointer gimp_circular_queue_get_last_offset(GimpCircularQueue* queue);
#define gimp_circular_queue_length(q) ((q)->end - (q)->start)
#define gimp_circular_queue_enqueue(q, a) gimp_circular_queue_enqueue_data(q, (void*)(&(a)))
#define gimp_circular_queue_index(q, type, i) (*(type*)gimp_circular_queue_get_nth_offset(q, i))
#define gimp_circular_queue_last(q, type) (*(type*)gimp_circular_queue_get_last_offset(q))
typedef struct _GimpJitterOptions GimpJitterOptions;
typedef struct _GimpFadeOptions GimpFadeOptions;
......@@ -77,7 +58,7 @@ struct _GimpGradientOptions
struct _GimpSmoothingOptions
{
gboolean use_smoothing;
gint smoothing_history;
gint smoothing_quality;
gdouble smoothing_factor;
};
......@@ -147,10 +128,6 @@ gboolean gimp_paint_options_get_gradient_color (GimpPaintOptions *paint_options,
gdouble pixel_dist,
GimpRGB *color);
GimpCoords gimp_paint_options_get_smoothed_coords (GimpPaintOptions *paint_options,
const GimpCoords *original_coords,
GimpCircularQueue *history);
GimpBrushApplicationMode
gimp_paint_options_get_brush_mode (GimpPaintOptions *paint_options);
......
......@@ -50,6 +50,8 @@
#include "gimp-intl.h"
static void gimp_paint_options_gui_reset_size (GtkWidget *button,
GimpPaintOptions *paint_options);
......@@ -174,7 +176,6 @@ gimp_paint_options_gui (GimpToolOptions *tool_options)
frame = smoothing_options_gui (options, tool_type);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
/* the "incremental" toggle */
if (tool_type == GIMP_TYPE_PENCIL_TOOL ||
......@@ -345,22 +346,21 @@ smoothing_options_gui (GimpPaintOptions *paint_options,
gtk_table_set_col_spacings (GTK_TABLE (table), 2);
frame = gimp_prop_expanding_frame_new (config, "use-smoothing",
_("Apply Smoothing"),
_("Smooth stroke"),
table, NULL);
gimp_prop_scale_entry_new (config, "smoothing-history",
gimp_prop_scale_entry_new (config, "smoothing-quality",
GTK_TABLE (table), 0, 0,
_("Quality:"),
1, 10, 1,
FALSE, 0, 100);
factor = gimp_prop_scale_entry_new (config, "smoothing-factor",
GTK_TABLE (table), 0, 1,
_("Factor:"),
1, 10, 1,
FALSE, 0, 100);
gimp_scale_entry_set_logarithmic (factor, TRUE);
return frame;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment