summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2013-06-24 16:28:53 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2013-06-24 16:28:53 -0400
commita1f858d3b207739e0719c1fc28003f1d9dd3965d (patch)
tree23c9c35f6b95e116f11354b0c78841036dcdc6bb /libs
parent0ce393f05144762a20d72975d0254ebca0789973 (diff)
an awful lot of tweaks to drawing details
Diffstat (limited to 'libs')
-rw-r--r--libs/canvas/canvas.cc1
-rw-r--r--libs/canvas/canvas/types.h9
-rw-r--r--libs/canvas/line.cc9
-rw-r--r--libs/canvas/rectangle.cc83
-rw-r--r--libs/canvas/types.cc36
-rw-r--r--libs/canvas/wave_view.cc74
6 files changed, 121 insertions, 91 deletions
diff --git a/libs/canvas/canvas.cc b/libs/canvas/canvas.cc
index 04929ca1af..dab8ce6f68 100644
--- a/libs/canvas/canvas.cc
+++ b/libs/canvas/canvas.cc
@@ -80,6 +80,7 @@ Canvas::render (Rect const & area, Cairo::RefPtr<Cairo::Context> const & context
/* there's a common area between the root and the requested
area, so render it.
*/
+
_root.render (*draw, context);
}
}
diff --git a/libs/canvas/canvas/types.h b/libs/canvas/canvas/types.h
index 37c0c213ea..de98ddb18f 100644
--- a/libs/canvas/canvas/types.h
+++ b/libs/canvas/canvas/types.h
@@ -25,6 +25,12 @@
#include <stdint.h>
#include <boost/optional.hpp>
+#include <cairomm/refptr.h>
+
+namespace Cairo {
+ struct Context;
+}
+
namespace ArdourCanvas
{
@@ -89,6 +95,9 @@ struct Rect
bool contains (Duple) const;
Rect fix () const;
+ Rect convert_to_device (Cairo::RefPtr<Cairo::Context>) const;
+ Rect convert_to_user (Cairo::RefPtr<Cairo::Context>) const;
+
Distance width () const {
return x1 - x0;
}
diff --git a/libs/canvas/line.cc b/libs/canvas/line.cc
index b6a802b8df..af2a0e47db 100644
--- a/libs/canvas/line.cc
+++ b/libs/canvas/line.cc
@@ -56,10 +56,15 @@ void
Line::render (Rect const & /*area*/, Cairo::RefPtr<Cairo::Context> context) const
{
setup_outline_context (context);
+
Duple p0 = item_to_window (Duple (_points[0].x, _points[0].y));
Duple p1 = item_to_window (Duple (_points[1].x, _points[1].y));
- context->move_to (p0.x, p0.y);
- context->line_to (p1.x, p1.y);
+
+ /* See Cairo FAQ on single pixel lines to understand why we add 0.5
+ */
+
+ context->move_to (p0.x + 0.5, p0.y + 0.5);
+ context->line_to (p1.x + 0.5, p1.y + 0.5);
context->stroke ();
}
diff --git a/libs/canvas/rectangle.cc b/libs/canvas/rectangle.cc
index 6ce62b0144..9512b69417 100644
--- a/libs/canvas/rectangle.cc
+++ b/libs/canvas/rectangle.cc
@@ -68,69 +68,40 @@ Rectangle::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) con
draw.y0 = max (self.y0, max (0.0, draw.y0 - boundary));
draw.y1 = min (self.y1, min (2000.0, draw.y1 + boundary));
+ Rect fill_rect = draw;
+ Rect stroke_rect = fill_rect.expand (0.5);
+
if (_fill) {
setup_fill_context (context);
-
- context->rectangle (draw.x0, draw.y0, draw.width(), draw.height());
-
- if (!_outline) {
- context->fill ();
- } else {
-
- /* special/common case: outline the entire rectangle is
- * requested, so just use the same path for the fill
- * and stroke.
- */
-
- if (_outline_what == What (LEFT|RIGHT|BOTTOM|TOP)) {
- context->fill_preserve();
- setup_outline_context (context);
- context->stroke ();
- } else {
- context->fill ();
- }
- }
- }
+ context->rectangle (fill_rect.x0, fill_rect.y0, fill_rect.width(), fill_rect.height());
+ context->fill ();
+ }
if (_outline) {
-
+
setup_outline_context (context);
- if (_outline_what == What (LEFT|RIGHT|BOTTOM|TOP)) {
-
- /* if we filled and use full outline, we are already
- * done. otherwise, draw the frame here.
- */
-
- if (!_fill) {
- context->rectangle (draw.x0, draw.y0, draw.width(), draw.height());
- context->stroke ();
- }
-
- } else {
-
- if (_outline_what & LEFT) {
- context->move_to (draw.x0, draw.y0);
- context->line_to (draw.x0, draw.y1);
- }
-
- if (_outline_what & BOTTOM) {
- context->move_to (draw.x0, draw.y1);
- context->line_to (draw.x1, draw.y1);
- }
-
- if (_outline_what & RIGHT) {
- context->move_to (draw.x1, draw.y0);
- context->line_to (draw.x1, draw.y1);
- }
-
- if (_outline_what & TOP) {
- context->move_to (draw.x0, draw.y0);
- context->line_to (draw.x1, draw.y0);
- }
-
- context->stroke ();
+ if (_outline_what & LEFT) {
+ context->move_to (stroke_rect.x0, stroke_rect.y0);
+ context->line_to (stroke_rect.x0, stroke_rect.y1);
}
+
+ if (_outline_what & BOTTOM) {
+ context->move_to (stroke_rect.x0, stroke_rect.y1);
+ context->line_to (stroke_rect.x1, stroke_rect.y1);
+ }
+
+ if (_outline_what & RIGHT) {
+ context->move_to (stroke_rect.x1, stroke_rect.y0);
+ context->line_to (stroke_rect.x1, stroke_rect.y1);
+ }
+
+ if (_outline_what & TOP) {
+ context->move_to (stroke_rect.x0, stroke_rect.y0);
+ context->line_to (stroke_rect.x1, stroke_rect.y0);
+ }
+
+ context->stroke ();
}
}
diff --git a/libs/canvas/types.cc b/libs/canvas/types.cc
index dfd934b126..a8c690bbbe 100644
--- a/libs/canvas/types.cc
+++ b/libs/canvas/types.cc
@@ -20,6 +20,9 @@
#include <algorithm>
#include <cfloat>
#include <cassert>
+
+#include <cairomm/context.h>
+
#include "canvas/types.h"
using namespace std;
@@ -118,6 +121,39 @@ Rect::fix () const
return r;
}
+Rect
+Rect::convert_to_device (Cairo::RefPtr<Cairo::Context> c) const
+{
+ Coord xa, ya, xb, yb;
+
+ xa = x0;
+ xb = x1;
+ ya = y0;
+ yb = y1;
+
+ c->user_to_device (xa, ya);
+ c->user_to_device (xb, yb);
+
+ return Rect (xa, ya, xb, yb);
+}
+
+
+Rect
+Rect::convert_to_user (Cairo::RefPtr<Cairo::Context> c) const
+{
+ Coord xa, ya, xb, yb;
+
+ xa = x0;
+ xb = x1;
+ ya = y0;
+ yb = y1;
+
+ c->device_to_user (xa, ya);
+ c->device_to_user (xb, yb);
+
+ return Rect (xa, ya, xb, yb);
+}
+
Duple
ArdourCanvas::operator- (Duple const & o)
{
diff --git a/libs/canvas/wave_view.cc b/libs/canvas/wave_view.cc
index 8a8b528b6f..2118838a03 100644
--- a/libs/canvas/wave_view.cc
+++ b/libs/canvas/wave_view.cc
@@ -178,6 +178,7 @@ WaveView::ensure_cache (framecnt_t start, framecnt_t end,
sample_start = max ((framepos_t) 0, (center - canvas_samples));
sample_end = min (center + canvas_samples, _region->source_length (0));
+#if 0
if (sample_end <= sample_start) {
cerr << "sample start = " << sample_start << endl;
cerr << "center+ = " << center<< endl;
@@ -188,13 +189,15 @@ WaveView::ensure_cache (framecnt_t start, framecnt_t end,
cerr << "END: " << sample_end << endl;
assert (false);
}
+#endif
start = floor (sample_start / (double) _samples_per_pixel);
end = ceil (sample_end / (double) _samples_per_pixel);
assert (end > start);
- cerr << name << " cache miss - new CE, span " << start << " .. " << end << " (" << sample_start << " .. " << sample_end << ")\n";
+ // cerr << name << " cache miss - new CE, span " << start << " .. " << end << " (" << sample_start << " .. " << sample_end << ")\n";
+
_cache = new CacheEntry (this, start, end, sample_start, sample_end);
}
@@ -254,7 +257,19 @@ WaveView::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) cons
// cerr << "Offset into image to place at zero: " << image_offset << endl;
context->rectangle (draw_start, draw.y0, draw_end - draw_start, draw.height());
- context->set_source (_cache->image(), self.x0 + image_offset, self.y0);
+
+ /* round image origin position to an exact pixel in device space to
+ * avoid blurring
+ */
+
+ double x = self.x0 + image_offset;
+ double y = self.y0;
+ context->user_to_device (x, y);
+ x = round (x);
+ y = round (y);
+ context->device_to_user (x, y);
+
+ context->set_source (_cache->image(), x, y);
context->fill ();
}
@@ -408,18 +423,6 @@ WaveView::region_resized ()
_pre_change_bounding_box = _bounding_box;
- frameoffset_t s = _region->start();
-
- if (s != _region_start) {
- /* if the region start changes, the information we have
- in the image cache is out of date and not useful
- since it will fragmented into little pieces. invalidate
- the cache.
- */
- _region_start = _region->start();
- invalidate_whole_cache ();
- }
-
_bounding_box_dirty = true;
compute_bounding_box ();
@@ -602,9 +605,6 @@ WaveView::CacheEntry::image ()
context->stroke ();
#else
- cerr << "draw, logscaled = " << _wave_view->_logscaled << " global " << WaveView::_global_logscaled << endl;
- cerr << "gradient depth: " << _wave_view->gradient_depth() << endl;
-
boost::scoped_array<LineTips> tips (new LineTips[_n_peaks]);
if (_wave_view->_shape == WaveView::Rectified) {
@@ -656,8 +656,8 @@ WaveView::CacheEntry::image ()
} else {
for (int i = 0; i < _n_peaks; ++i) {
- tips[i].top = floor (position (_peaks[i].min));
- tips[i].bot = ceil (position (_peaks[i].max));
+ tips[i].top = position (_peaks[i].min);
+ tips[i].bot = position (_peaks[i].max);
}
}
}
@@ -687,7 +687,7 @@ WaveView::CacheEntry::image ()
/* generate a new color for the middle of the gradient */
double h, s, v;
color_to_hsv (_wave_view->_fill_color, h, s, v);
- /* tone down the saturation */
+ /* change v towards white */
v *= 1.0 - _wave_view->gradient_depth();
Color center = hsv_to_color (h, s, v, a);
color_to_rgba (center, r, g, b, a);
@@ -695,24 +695,26 @@ WaveView::CacheEntry::image ()
context->set_source (gradient);
} else {
- cerr << "\tno gradient\n";
set_source_rgba (context, _wave_view->_fill_color);
}
+ /* ensure single-pixel lines */
+
context->set_line_width (0.5);
+ context->translate (0.5, 0.0);
/* draw the lines */
-
+
if (_wave_view->_shape == WaveView::Rectified) {
for (int i = 0; i < _n_peaks; ++i) {
- context->move_to (i + 0.5, tips[i].top + 0.5); /* down 1 pixel */
- context->line_to (i + 0.5, tips[i].bot);
+ context->move_to (i, tips[i].top); /* down 1 pixel */
+ context->line_to (i, tips[i].bot);
context->stroke ();
}
} else {
for (int i = 0; i < _n_peaks; ++i) {
- context->move_to (i + 0.5, tips[i].top + 0.5); /* down 1 pixel */
- context->line_to (i + 0.5, tips[i].bot - 0.5); /* up 1 pixel */
+ context->move_to (i, tips[i].top);
+ context->line_to (i, tips[i].bot);
context->stroke ();
}
}
@@ -721,14 +723,16 @@ WaveView::CacheEntry::image ()
* modelled on pyramix, except that we add clipping indicators.
*/
- context->set_source_rgb (0, 0, 0);
+ context->set_source_rgba (0, 0, 0, 1.0);
for (int i = 0; i < _n_peaks; ++i) {
- context->rectangle (i + 0.5, tips[i].top, 0.5, 0.5);
- context->fill ();
+ context->move_to (i, tips[i].top);
+ context->rel_line_to (0, 1.0);
+ context->stroke ();
if (_wave_view->_shape != WaveView::Rectified) {
- context->rectangle (i + 0.5, tips[i].bot, 0.5, 0.5);
- context->fill ();
+ context->move_to (i, tips[i].bot);
+ context->rel_line_to (0, -1.0);
+ context->stroke ();
}
}
#endif
@@ -749,13 +753,17 @@ WaveView::CacheEntry::image ()
Coord
WaveView::CacheEntry::position (double s) const
{
+ /* it is important that this returns an integral value, so that we
+ can ensure correct single pixel behaviour.
+ */
+
switch (_wave_view->_shape) {
case Rectified:
- return _wave_view->_height - (s * _wave_view->_height);
+ return floor (_wave_view->_height - (s * _wave_view->_height));
default:
break;
}
- return (1.0-s) * (_wave_view->_height / 2.0);
+ return floor ((1.0-s) * (_wave_view->_height / 2.0));
}
void