From 3517286a9404d556c384276d63b73b588fadbcfe Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 3 Jan 2014 22:24:11 +0000 Subject: Draw and layout performance improvements. git-svn-id: http://svn.drobilla.net/lad/trunk/ganv@5248 a436a847-0d15-0410-975c-d299462d15a1 --- src/Canvas.cpp | 18 +++++++------ src/box.c | 38 ++++++++++++-------------- src/canvas-base.c | 79 ++++++++++++++++++++++--------------------------------- src/edge.c | 11 +++++--- src/port.c | 12 ++++----- src/text.c | 8 +++--- 6 files changed, 76 insertions(+), 90 deletions(-) (limited to 'src') 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 -- cgit v1.2.1