Various fixes and efficiency improvements to the drawing backend. Among other stuff, stroked lines with a width greater than 1 have anti-aliased butts now. There are some bugs left regarding text rendering.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12761 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2005-05-22 12:12:56 +00:00
parent 63381b0c49
commit ac167e6ead
2 changed files with 69 additions and 19 deletions
@@ -838,14 +838,14 @@ void
DisplayDriverPainter::StrokeRect(const BRect &r, const RGBColor &color) DisplayDriverPainter::StrokeRect(const BRect &r, const RGBColor &color)
{ {
if (Lock()) { if (Lock()) {
fGraphicsCard->HideSoftwareCursor();
// support invalid rects // support invalid rects
BRect vr(min_c(r.left, r.right), BRect vr(min_c(r.left, r.right),
min_c(r.top, r.bottom), min_c(r.top, r.bottom),
max_c(r.left, r.right), max_c(r.left, r.right),
max_c(r.top, r.bottom)); max_c(r.top, r.bottom));
fGraphicsCard->HideSoftwareCursor(vr);
fPainter->StrokeRect(vr, color.GetColor32()); fPainter->StrokeRect(vr, color.GetColor32());
/* fGraphicsCard->Invalidate(fPainter->ClipRect(BRect(vr.left, vr.top, /* fGraphicsCard->Invalidate(fPainter->ClipRect(BRect(vr.left, vr.top,
@@ -868,7 +868,15 @@ void
DisplayDriverPainter::StrokeRect(const BRect &r, const DrawData *d) DisplayDriverPainter::StrokeRect(const BRect &r, const DrawData *d)
{ {
if (Lock()) { if (Lock()) {
fGraphicsCard->HideSoftwareCursor(); // support invalid rects
BRect vr(min_c(r.left, r.right),
min_c(r.top, r.bottom),
max_c(r.left, r.right),
max_c(r.top, r.bottom));
float extend = -ceilf(d->PenSize() / 2.0);
vr.InsetBy(extend, extend);
fGraphicsCard->HideSoftwareCursor(vr);
fPainter->SetDrawData(d); fPainter->SetDrawData(d);
BRect touched = fPainter->StrokeRect(r); BRect touched = fPainter->StrokeRect(r);
@@ -974,6 +982,7 @@ DisplayDriverPainter::DrawString(const char *string, const int32 &length,
const BPoint &pt, DrawData *d) const BPoint &pt, DrawData *d)
{ {
if (Lock()) { if (Lock()) {
fPainter->SetDrawData(d);
//bigtime_t now = system_time(); //bigtime_t now = system_time();
// TODO: BoundingBox is quite slow!! Optimizing it will be beneficial. // TODO: BoundingBox is quite slow!! Optimizing it will be beneficial.
// Cursiously, the actual DrawString after it is actually faster!?! // Cursiously, the actual DrawString after it is actually faster!?!
@@ -984,8 +993,6 @@ DisplayDriverPainter::DrawString(const char *string, const int32 &length,
//printf("bounding box '%s': %lld µs\n", string, system_time() - now); //printf("bounding box '%s': %lld µs\n", string, system_time() - now);
fGraphicsCard->HideSoftwareCursor(b); fGraphicsCard->HideSoftwareCursor(b);
fPainter->SetDrawData(d);
//now = system_time(); //now = system_time();
BRect touched = fPainter->DrawString(string, length, pt); BRect touched = fPainter->DrawString(string, length, pt);
//printf("drawing string: %lld µs\n", system_time() - now); //printf("drawing string: %lld µs\n", system_time() - now);
+57 -14
View File
@@ -30,6 +30,21 @@
#include "Painter.h" #include "Painter.h"
#if ALIASED_DRAWING
// in this case, we _cannot_ use the outline rasterizer.
# define USE_OUTLINE_RASTERIZER 0
#else
// in this case, we can optionally use the outline rasterizer (faster).
// NOTE: The outline rasterizer is different from the "general purpose"
// rasterizer and can speed up the stroking of lines. It has some problems
// though, for example the butts of the lines are not anti-aliased. So we
// use the much more powerfull general purpose rasterizer, and live with the
// performance hit for now. See _StrokePath().
// NOTE: The outline rasterizer will still be used for lines with 1 pixel width!
# define USE_OUTLINE_RASTERIZER 0
#endif
int int
roundf(float v) roundf(float v)
{ {
@@ -216,7 +231,11 @@ Painter::SetPenSize(float size)
{ {
if (fPenSize != size) { if (fPenSize != size) {
fPenSize = size; fPenSize = size;
#if USE_OUTLINE_RASTERIZER
// NOTE: _UpdateLineWidth() updates the line profile which is quite a heavy resource!
// fortunately, we don't need it when using the general purpose rasterizer
_UpdateLineWidth(); _UpdateLineWidth();
#endif
} }
} }
@@ -531,9 +550,8 @@ Painter::StrokeRect(const BRect& r) const
// support invalid rects // support invalid rects
BPoint a(min_c(r.left, r.right), min_c(r.top, r.bottom)); BPoint a(min_c(r.left, r.right), min_c(r.top, r.bottom));
BPoint b(max_c(r.left, r.right), max_c(r.top, r.bottom)); BPoint b(max_c(r.left, r.right), max_c(r.top, r.bottom));
bool centerOffset = fPenSize == 1.0; _Transform(&a, false);
_Transform(&a, centerOffset); _Transform(&b, false);
_Transform(&b, centerOffset);
// first, try an optimized version // first, try an optimized version
if (fPenSize == 1.0 && if (fPenSize == 1.0 &&
@@ -552,11 +570,24 @@ Painter::StrokeRect(const BRect& r) const
} }
} }
if (fmodf(fPenSize, 2.0) != 0.0) {
// shift coords to center of pixels
a.x += 0.5;
a.y += 0.5;
b.x += 0.5;
b.y += 0.5;
}
agg::path_storage path; agg::path_storage path;
path.move_to(a.x, a.y); path.move_to(a.x, a.y);
path.line_to(b.x, a.y); if (a.x == b.x || a.y == b.y) {
path.line_to(b.x, b.y); // special case rects with one pixel height or width
path.line_to(a.x, b.y); path.line_to(b.x, b.y);
} else {
path.line_to(b.x, a.y);
path.line_to(b.x, b.y);
path.line_to(a.x, b.y);
}
path.close_polygon(); path.close_polygon();
return _StrokePath(path); return _StrokePath(path);
@@ -664,6 +695,8 @@ Painter::StrokeRoundRect(const BRect& r, float xRadius, float yRadius) const
BPoint lt(r.left, r.top); BPoint lt(r.left, r.top);
BPoint rb(r.right, r.bottom); BPoint rb(r.right, r.bottom);
bool centerOffset = fPenSize == 1.0; bool centerOffset = fPenSize == 1.0;
// TODO: use this when using _StrokePath()
// bool centerOffset = fmodf(fPenSize, 2.0) != 0.0;
_Transform(&lt, centerOffset); _Transform(&lt, centerOffset);
_Transform(&rb, centerOffset); _Transform(&rb, centerOffset);
@@ -687,6 +720,8 @@ Painter::StrokeRoundRect(const BRect& r, float xRadius, float yRadius) const
agg::rounded_rect outer; agg::rounded_rect outer;
outer.rect(lt.x, lt.y, rb.x, rb.y); outer.rect(lt.x, lt.y, rb.x, rb.y);
outer.radius(xRadius, yRadius); outer.radius(xRadius, yRadius);
fRasterizer->reset();
fRasterizer->add_path(outer); fRasterizer->add_path(outer);
// don't add an inner hole if the "size is negative", this avoids some // don't add an inner hole if the "size is negative", this avoids some
@@ -1227,6 +1262,7 @@ Painter::_DrawEllipse(BPoint center, float xRadius, float yRadius,
yRadius + inset, yRadius + inset,
divisions); divisions);
fRasterizer->reset();
fRasterizer->add_path(outer); fRasterizer->add_path(outer);
fRasterizer->add_path(inner); fRasterizer->add_path(inner);
@@ -1456,19 +1492,25 @@ template<class VertexSource>
BRect BRect
Painter::_StrokePath(VertexSource& path) const Painter::_StrokePath(VertexSource& path) const
{ {
#if ALIASED_DRAWING #if USE_OUTLINE_RASTERIZER
if (fPenSize > 1.0) { fOutlineRasterizer->add_path(path);
#else
// if (fPenSize > 1.0) {
agg::conv_stroke<VertexSource> stroke(path); agg::conv_stroke<VertexSource> stroke(path);
stroke.line_join(agg::round_join); // TODO: Investigate this for shapes. Maybe we are supposed to
// use the settings from DrawData! Would make some sense!
// stroke.line_join(agg::round_join);
// stroke.line_cap(agg::butt_cap);
stroke.width(fPenSize); stroke.width(fPenSize);
fRasterizer->reset();
fRasterizer->add_path(stroke); fRasterizer->add_path(stroke);
agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer); agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer);
} else { // } else {
fOutlineRasterizer->add_path(path); // TODO: update to AGG 2.3 to get rid of the remaining problems:
} // rects which are 2 or 1 pixel high/wide don't render at all.
#else // fOutlineRasterizer->add_path(path);
fOutlineRasterizer->add_path(path); // }
#endif #endif
BRect touched = _BoundingBox(path); BRect touched = _BoundingBox(path);
@@ -1483,6 +1525,7 @@ template<class VertexSource>
BRect BRect
Painter::_FillPath(VertexSource& path) const Painter::_FillPath(VertexSource& path) const
{ {
fRasterizer->reset();
fRasterizer->add_path(path); fRasterizer->add_path(path);
agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer); agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer);