summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2014-01-03 22:24:11 +0000
committerDavid Robillard <d@drobilla.net>2014-01-03 22:24:11 +0000
commit3517286a9404d556c384276d63b73b588fadbcfe (patch)
tree21d755eaeebace222216b3ab294ea200171fe3a2 /src
parent9191aae81ab497d9cbf5a256b2b2e9dbf1af5d67 (diff)
downloadganv-3517286a9404d556c384276d63b73b588fadbcfe.tar.gz
ganv-3517286a9404d556c384276d63b73b588fadbcfe.tar.bz2
ganv-3517286a9404d556c384276d63b73b588fadbcfe.zip
Draw and layout performance improvements.
git-svn-id: http://svn.drobilla.net/lad/trunk/ganv@5248 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r--src/Canvas.cpp18
-rw-r--r--src/box.c38
-rw-r--r--src/canvas-base.c79
-rw-r--r--src/edge.c11
-rw-r--r--src/port.c12
-rw-r--r--src/text.c8
6 files changed, 76 insertions, 90 deletions
diff --git a/src/Canvas.cpp b/src/Canvas.cpp
index ca28025..73e78cb 100644
--- a/src/Canvas.cpp
+++ b/src/Canvas.cpp
@@ -716,16 +716,18 @@ GanvCanvasImpl::layout_dot(const std::string& filename)
#ifdef GANV_FDGL
inline Region
-get_region(const GanvNode* node)
+get_region(GanvNode* node)
{
+ GanvItem* item = &node->item;
+
double x1, y1, x2, y2;
- ganv_item_get_bounds(GANV_ITEM(node), &x1, &y1, &x2, &y2);
+ ganv_item_get_bounds(item, &x1, &y1, &x2, &y2);
Region reg;
reg.area.x = x2 - x1;
reg.area.y = y2 - y1;
- reg.pos.x = GANV_ITEM(node)->x + (reg.area.x / 2.0);
- reg.pos.y = GANV_ITEM(node)->y + (reg.area.y / 2.0);
+ reg.pos.x = item->x + (reg.area.x / 2.0);
+ reg.pos.y = item->y + (reg.area.y / 2.0);
// No need for i2w here since we only care about top-level items
return reg;
@@ -806,7 +808,7 @@ GanvCanvasImpl::layout_calculate(double dur, bool update)
if (!GANV_IS_MODULE(*i) && !GANV_IS_CIRCLE(*i)) {
continue;
}
- GanvNode* const node = GANV_NODE(*i);
+ GanvNode* const node = *i;
const Region reg = get_region(node);
GanvNode* partner = ganv_node_get_partner(node);
@@ -844,7 +846,7 @@ GanvCanvasImpl::layout_calculate(double dur, bool update)
if (i == j || (!GANV_IS_MODULE(*i) && !GANV_IS_CIRCLE(*i))) {
continue;
}
- GanvNode* const node2 = GANV_NODE(*j);
+ GanvNode* const node2 = *j;
if ((!node2->impl->has_in_edges && !node2->impl->has_out_edges) &&
!node2->impl->is_source) {
continue;
@@ -861,7 +863,7 @@ GanvCanvasImpl::layout_calculate(double dur, bool update)
continue;
}
- GanvNode* const node = GANV_NODE(*i);
+ GanvNode* const node = *i;
static const float damp = 0.3; // Velocity damping
@@ -887,7 +889,7 @@ GanvCanvasImpl::layout_calculate(double dur, bool update)
}
// Update position
- GanvItem* item = GANV_ITEM(node);
+ GanvItem* item = &node->item;
const double x0 = item->x;
const double y0 = item->y;
const Vector dpos = vec_mult(node->impl->vel, dur);
diff --git a/src/box.c b/src/box.c
index 8130cef..40352e4 100644
--- a/src/box.c
+++ b/src/box.c
@@ -134,15 +134,10 @@ ganv_box_bounds_item(const GanvBoxCoords* coords,
double* x1, double* y1,
double* x2, double* y2)
{
- *x1 = MIN(coords->x1, coords->x2) - coords->border_width;
- *y1 = MIN(coords->y1, coords->y2) - coords->border_width;
- *x2 = MAX(coords->x1, coords->x2) + coords->border_width;
- *y2 = MAX(coords->y1, coords->y2) + coords->border_width;
-
- if (coords->stacked) {
- *x2 += STACKED_OFFSET;
- *y2 += STACKED_OFFSET;
- }
+ *x1 = coords->x1 - coords->border_width;
+ *y1 = coords->y1 - coords->border_width;
+ *x2 = coords->x2 + coords->border_width + (coords->stacked * STACKED_OFFSET);
+ *y2 = coords->y2 + coords->border_width + (coords->stacked * STACKED_OFFSET);
}
void
@@ -173,7 +168,7 @@ ganv_box_bounds(GanvItem* item,
double* x2, double* y2)
{
// Note this will not be correct if children are outside the box bounds
- GanvBox* box = GANV_BOX(item);
+ GanvBox* box = (GanvBox*)item;
ganv_box_bounds_item(&box->impl->coords, x1, y1, x2, y2);
ganv_item_i2w_pair(item, x1, y1, x2, y2);
}
@@ -196,6 +191,8 @@ ganv_box_update(GanvItem* item, int flags)
impl->old_coords = impl->coords;
coords_i2w(item, &impl->old_coords);
+ ganv_box_normalize(box);
+
// Get bounding box
double x1, x2, y1, y2;
ganv_box_bounds(item, &x1, &y1, &x2, &y2);
@@ -474,17 +471,16 @@ ganv_box_class_init(GanvBoxClass* klass)
void
ganv_box_normalize(GanvBox* box)
{
- GanvBoxCoords* coords = &box->impl->coords;
-
- const double x1 = coords->x1;
- const double y1 = coords->y1;
- const double x2 = coords->x2;
- const double y2 = coords->y2;
-
- coords->x1 = MIN(x1, x2);
- coords->y1 = MIN(y1, y2);
- coords->x2 = MAX(x1, x2);
- coords->y2 = MAX(y1, y2);
+ if (box->impl->coords.x2 < box->impl->coords.x1) {
+ const double tmp = box->impl->coords.x1;
+ box->impl->coords.x1 = box->impl->coords.x2;
+ box->impl->coords.x2 = tmp;
+ }
+ if (box->impl->coords.y2 < box->impl->coords.y1) {
+ const double tmp = box->impl->coords.y1;
+ box->impl->coords.y1 = box->impl->coords.y2;
+ box->impl->coords.y2 = tmp;
+ }
}
double
diff --git a/src/canvas-base.c b/src/canvas-base.c
index 8d8b8d1..e30a517 100644
--- a/src/canvas-base.c
+++ b/src/canvas-base.c
@@ -673,6 +673,12 @@ ganv_item_grab_focus(GanvItem* item)
}
}
+static void
+ganv_item_default_bounds(GanvItem* item, double* x1, double* y1, double* x2, double* y2)
+{
+ *x1 = *y1 = *x2 = *y2 = 0.0;
+}
+
/**
* ganv_item_get_bounds:
* @item: A canvas item.
@@ -687,20 +693,7 @@ ganv_item_grab_focus(GanvItem* item)
void
ganv_item_get_bounds(GanvItem* item, double* x1, double* y1, double* x2, double* y2)
{
- g_return_if_fail(GANV_IS_ITEM(item));
-
- if (GANV_ITEM_GET_CLASS(item)->bounds) {
- // Get bounds from item class
- (*GANV_ITEM_GET_CLASS(item)->bounds)(item, x1, y1, x2, y2);
-
- // Make bounds relative to the item's parent coordinate system
- *x1 -= item->x;
- *y1 -= item->y;
- *x2 -= item->x;
- *y2 -= item->y;
- } else {
- *x1 = *y1 = *x2 = *y2 = 0.0;
- }
+ GANV_ITEM_GET_CLASS(item)->bounds(item, x1, y1, x2, y2);
}
/**
@@ -1748,46 +1741,37 @@ ganv_canvas_base_paint_rect(GanvCanvasBase* canvas, gint x0, gint y0, gint x1, g
static gint
ganv_canvas_base_expose(GtkWidget* widget, GdkEventExpose* event)
{
- GanvCanvasBase* canvas;
- GdkRectangle* rects;
- gint n_rects;
- int i;
-
- canvas = GANV_CANVAS_BASE(widget);
-
- if (!GTK_WIDGET_DRAWABLE(widget) || (event->window != canvas->layout.bin_window)) {
+ GanvCanvasBase* canvas = GANV_CANVAS_BASE(widget);
+ if (!GTK_WIDGET_DRAWABLE(widget) ||
+ (event->window != canvas->layout.bin_window)) {
return FALSE;
}
-#ifdef VERBOSE
- g_print("Expose\n");
-#endif
-
- gdk_region_get_rectangles(event->region, &rects, &n_rects);
-
- for (i = 0; i < n_rects; i++) {
- const int x0 = rects[i].x - canvas->zoom_xofs;
- const int y0 = rects[i].y - canvas->zoom_yofs;
- const int x1 = rects[i].x + rects[i].width - canvas->zoom_xofs;
- const int y1 = rects[i].y + rects[i].height - canvas->zoom_yofs;
-
- if (canvas->need_update || canvas->need_redraw) {
- /* Update or drawing is scheduled, so just mark exposed area as dirty */
- ganv_canvas_base_request_redraw(canvas, x0, y0, x1, y1);
- } else {
- /* No pending updates, draw exposed area immediately */
- ganv_canvas_base_paint_rect(canvas, x0, y0, x1, y1);
+ /* Find a single bounding rectangle for all rectangles in the region.
+ Since drawing the root group is O(n) and thus very expensive for large
+ canvases, it's much faster to do a single paint than many, even though
+ more area may be painted that way. With a better group implementation,
+ it would likely be better to paint each changed rectangle separately. */
+ GdkRectangle clip;
+ gdk_region_get_clipbox(event->region, &clip);
+
+ const int x2 = clip.x + clip.width;
+ const int y2 = clip.y + clip.height;
+
+ if (canvas->need_update || canvas->need_redraw) {
+ /* Update or drawing is scheduled, so just mark exposed area as dirty */
+ ganv_canvas_base_request_redraw(canvas, clip.x, clip.y, x2, y2);
+ } else {
+ /* No pending updates, draw exposed area immediately */
+ ganv_canvas_base_paint_rect(canvas, clip.x, clip.y, x2, y2);
- /* And call expose on parent container class */
- if (GTK_WIDGET_CLASS(canvas_parent_class)->expose_event) {
- (*GTK_WIDGET_CLASS(canvas_parent_class)->expose_event)(
- widget, event);
- }
+ /* And call expose on parent container class */
+ if (GTK_WIDGET_CLASS(canvas_parent_class)->expose_event) {
+ (*GTK_WIDGET_CLASS(canvas_parent_class)->expose_event)(
+ widget, event);
}
}
- g_free(rects);
-
return FALSE;
}
@@ -2515,4 +2499,5 @@ ganv_item_class_init(GanvItemClass* klass)
klass->unmap = ganv_item_unmap;
klass->update = ganv_item_update;
klass->point = ganv_item_point;
+ klass->bounds = ganv_item_default_bounds;
}
diff --git a/src/edge.c b/src/edge.c
index d6ca68a..2743100 100644
--- a/src/edge.c
+++ b/src/edge.c
@@ -267,10 +267,13 @@ ganv_edge_get_coords(const GanvEdge* edge, GanvEdgeCoords* coords)
coords->handle_x = coords->x1 + (dx / 2.0);
coords->handle_y = coords->y1 + (dy / 2.0);
- coords->cx1 = coords->x1 + (coords->cx1 * (ceil(fabs(dx)) / 4.0));
- coords->cy1 = coords->y1 + (coords->cy1 * (ceil(fabs(dy)) / 4.0));
- coords->cx2 = coords->x2 + (coords->cx2 * (ceil(fabs(dx)) / 4.0));
- coords->cy2 = coords->y2 + (coords->cy2 * (ceil(fabs(dy)) / 4.0));
+ const double abs_dx = fabs(dx);
+ const double abs_dy = fabs(dy);
+
+ coords->cx1 = coords->x1 + (coords->cx1 * (abs_dx / 4.0));
+ coords->cy1 = coords->y1 + (coords->cy1 * (abs_dy / 4.0));
+ coords->cx2 = coords->x2 + (coords->cx2 * (abs_dx / 4.0));
+ coords->cy2 = coords->y2 + (coords->cy2 * (abs_dy / 4.0));
}
static void
diff --git a/src/port.c b/src/port.c
index 29a7a10..4750064 100644
--- a/src/port.c
+++ b/src/port.c
@@ -164,9 +164,9 @@ ganv_port_tail_vector(const GanvNode* self,
double* dx,
double* dy)
{
- GanvItem* item = GANV_ITEM(self);
GanvPort* port = GANV_PORT(self);
- GanvCanvas* canvas = GANV_CANVAS(GANV_ITEM(self)->canvas);
+ GanvItem* item = &port->box.node.item;
+ GanvCanvas* canvas = GANV_CANVAS(item->canvas);
const double px = item->x;
const double py = item->y;
@@ -186,7 +186,7 @@ ganv_port_tail_vector(const GanvNode* self,
break;
}
- ganv_item_i2w(GANV_ITEM(self)->parent, x, y);
+ ganv_item_i2w(item->parent, x, y);
}
static void
@@ -197,9 +197,9 @@ ganv_port_head_vector(const GanvNode* self,
double* dx,
double* dy)
{
- GanvItem* item = GANV_ITEM(self);
GanvPort* port = GANV_PORT(self);
- GanvCanvas* canvas = GANV_CANVAS(GANV_ITEM(self)->canvas);
+ GanvItem* item = &port->box.node.item;
+ GanvCanvas* canvas = GANV_CANVAS(item->canvas);
const double px = item->x;
const double py = item->y;
@@ -219,7 +219,7 @@ ganv_port_head_vector(const GanvNode* self,
break;
}
- ganv_item_i2w(GANV_ITEM(self)->parent, x, y);
+ ganv_item_i2w(item->parent, x, y);
}
static void
diff --git a/src/text.c b/src/text.c
index 528a842..3d14c64 100644
--- a/src/text.c
+++ b/src/text.c
@@ -217,10 +217,10 @@ ganv_text_bounds_item(GanvItem* item,
ganv_text_layout(text);
}
- *x1 = MIN(impl->coords.x, impl->coords.x + impl->coords.width);
- *y1 = MIN(impl->coords.y, impl->coords.y + impl->coords.height);
- *x2 = MAX(impl->coords.x, impl->coords.x + impl->coords.width);
- *y2 = MAX(impl->coords.y, impl->coords.y + impl->coords.height);
+ *x1 = impl->coords.x;
+ *y1 = impl->coords.y;
+ *x2 = impl->coords.x + impl->coords.width;
+ *y2 = impl->coords.y + impl->coords.height;
}
static void