refactored DrawBitmap to support a version BBitmaps and one for ServerBitmaps, implemented InvertRect, but that was a while ago, and I didn't test it

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@11960 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2005-03-23 20:31:33 +00:00
parent ffc80308e6
commit a0c67cdb39
2 changed files with 221 additions and 94 deletions

View File

@ -10,3 +10,14 @@ B_OP_ALPHA (with B_ALPHA_OVERLAY) seems to *assign* the source alpha to the dest
The BView pen location appears to be integer coords, which spoils the pen location version of BView::DrawString() for rotated text.
Dest alpha is actually only interesting when drawing into a BBitmap. When drawing into the frame buffer, dest alpha is logically 255, it wouldn't even need to be assigned. Maybe we could save a few CPU cycles if we adjust the DrawingMode classes accordingly. For now, the modes work as expected when drawing into a BBitmap.
Current comparision timings:
drawing_mode: B_OP_COPY
pen size: 1.0
ellipse test: 5.15
ellipse test AA: 13.90
pen size: 2.0
ellipse test: 15.2
ellipse test AA: 11.0

View File

@ -22,6 +22,8 @@
#include "PatternHandler.h"
#include "RenderingBuffer.h"
#include "ShapeConverter.h"
#include "ServerBitmap.h"
#include "ServerFont.h"
#include "Painter.h"
@ -581,98 +583,71 @@ void
Painter::DrawBitmap(const BBitmap* bitmap,
BRect bitmapRect, BRect viewRect) const
{
typedef agg::span_allocator<agg::rgba8> span_alloc_type;
typedef agg::span_interpolator_linear<> interpolator_type;
typedef agg::span_image_filter_rgba32_nn<agg::order_bgra32,
interpolator_type> span_gen_type;
typedef agg::renderer_scanline_aa<renderer_base, span_gen_type> image_renderer_type;
if (bitmap && bitmap->IsValid()) {
// the native bitmap coordinate system
// (can have left top corner offset)
BRect actualBitmapRect(bitmap->Bounds());
if (bitmap && bitmap->IsValid()
&& bitmapRect.IsValid() && bitmapRect.Intersects(bitmap->Bounds())
&& viewRect.IsValid()) {
BRect actualBitmapRect = bitmap->Bounds();
// compensate for the lefttop offset the actualBitmapRect might have
// NOTE: I have no clue why this next call gives a wrong result!
// According to the BeBook, bitmapRect is supposed to be in native
// bitmap space!
// bitmapRect.OffsetBy(-actualBitmapRect.left, -actualBitmapRect.top);
actualBitmapRect.OffsetBy(-actualBitmapRect.left, -actualBitmapRect.top);
// calculate the scaling
double xScale = (viewRect.Width() + 1) / (bitmapRect.Width() + 1);
double yScale = (viewRect.Height() + 1) / (bitmapRect.Height() + 1);
// constrain rect to passed bitmap bounds
// and transfer the changes to the viewRect
if (bitmapRect.left < actualBitmapRect.left) {
float diff = actualBitmapRect.left - bitmapRect.left;
viewRect.left += diff * xScale;
bitmapRect.left = actualBitmapRect.left;
}
if (bitmapRect.top < actualBitmapRect.top) {
float diff = actualBitmapRect.top - bitmapRect.top;
viewRect.top += diff;
bitmapRect.top = actualBitmapRect.top;
}
if (bitmapRect.right > actualBitmapRect.right) {
float diff = bitmapRect.right - actualBitmapRect.right;
viewRect.right -= diff;
bitmapRect.right = actualBitmapRect.right;
}
if (bitmapRect.bottom > actualBitmapRect.bottom) {
float diff = bitmapRect.right - actualBitmapRect.bottom;
viewRect.bottom -= diff;
bitmapRect.bottom = actualBitmapRect.bottom;
}
float xOffset = viewRect.left - (bitmapRect.left * xScale);
float yOffset = viewRect.top - (bitmapRect.top * yScale);
// source rendering buffer
agg::rendering_buffer srcBuffer;
srcBuffer.attach((uint8*)bitmap->Bits(),
actualBitmapRect.IntegerWidth() + 1,
actualBitmapRect.IntegerHeight() + 1,
(uint32)actualBitmapRect.IntegerWidth() + 1,
(uint32)actualBitmapRect.IntegerHeight() + 1,
bitmap->BytesPerRow());
agg::trans_affine srcMatrix;
// srcMatrix *= agg::trans_affine_translation(-actualBitmapRect.left, -actualBitmapRect.top);
srcMatrix *= agg::trans_affine_scaling(fScale, fScale);
srcMatrix *= agg::trans_affine_translation(fOrigin.x, fOrigin.y);
agg::trans_affine imgMatrix;
imgMatrix *= agg::trans_affine_scaling(xScale, yScale);
imgMatrix *= agg::trans_affine_translation(xOffset, yOffset);
imgMatrix *= agg::trans_affine_scaling(fScale, fScale);
imgMatrix *= agg::trans_affine_translation(fOrigin.x, fOrigin.y);
imgMatrix.invert();
span_alloc_type sa;
interpolator_type interpolator(imgMatrix);
span_gen_type sg(sa, srcBuffer, agg::rgba(0, 0, 0, 0), interpolator);
image_renderer_type ri(*fBaseRenderer, sg);
agg::rasterizer_scanline_aa<> pf;
agg::scanline_u8 sl;
// path encloses image
agg::path_storage path;
path.move_to(viewRect.left, viewRect.top);
path.line_to(viewRect.right + 1, viewRect.top);
path.line_to(viewRect.right + 1, viewRect.bottom + 1);
path.line_to(viewRect.left, viewRect.bottom + 1);
path.close_polygon();
agg::conv_transform<agg::path_storage> tr(path, srcMatrix);
pf.add_path(tr);
agg::render_scanlines(pf, sl, ri);
_DrawBitmap(srcBuffer, bitmap->ColorSpace(), actualBitmapRect, bitmapRect, viewRect);
}
}
// DrawBitmap
void
Painter::DrawBitmap(const ServerBitmap* bitmap,
BRect bitmapRect, BRect viewRect) const
{
if (bitmap && bitmap->InitCheck()) {
// the native bitmap coordinate system
BRect actualBitmapRect(bitmap->Bounds());
agg::rendering_buffer srcBuffer;
srcBuffer.attach(bitmap->Bits(),
bitmap->Width(),
bitmap->Height(),
bitmap->BytesPerRow());
_DrawBitmap(srcBuffer, bitmap->ColorSpace(), actualBitmapRect, bitmapRect, viewRect);
}
}
// #pragma mark -
// FillRegion
void
Painter::FillRegion(const BRegion* region, const pattern& p = B_SOLID_HIGH) const
{
BRegion copy(*region);
int32 count = copy.CountRects();
for (int32 i = 0; i < count; i++) {
FillRect(copy.RectAt(i), p);
}
}
// InvertRect
void
Painter::InvertRect(const BRect& r) const
{
BRegion region(r);
if (fClippingRegion) {
region.IntersectWith(fClippingRegion);
}
// implementation only for B_RGB32 at the moment
int32 count = region.CountRects();
for (int32 i = 0; i < count; i++) {
BRect r = region.RectAt(i);
_Transform(&r);
_InvertRect32(r);
}
}
// #pragma mark -
// _MakeEmpty
@ -761,6 +736,25 @@ Painter::_Transform(const float& width) const
return w;
}
// _Transform
void
Painter::_Transform(BRect* rect) const
{
// TODO integrate this function more
rect->right++;
rect->bottom++;
rect->left += fOrigin.x;
rect->top += fOrigin.y;
rect->right += fOrigin.x;
rect->bottom += fOrigin.y;
rect->left *= fScale;
rect->top *= fScale;
rect->right *= fScale;
rect->bottom *= fScale;
rect->right--;
rect->bottom--;
}
// _RebuildClipping
void
Painter::_RebuildClipping()
@ -776,16 +770,17 @@ Painter::_RebuildClipping()
// though I was unable to figure out the difference
BPoint lt(r.LeftTop());
BPoint rb(r.RightBottom());
rb += BPoint(1.0, 1.0);
// _Transform(&lt, false);
// _Transform(&rb, false);
lt += fOrigin;
lt.x *= fScale;
lt.y *= fScale;
rb += fOrigin;
rb.x *= fScale;
rb.y *= fScale;
rb -= BPoint(1.0, 1.0);
// offset to bottom right corner of pixel before transformation
rb += BPoint(1.0, 1.0);
// apply transformation
lt += fOrigin;
lt.x *= fScale;
lt.y *= fScale;
rb += fOrigin;
rb.x *= fScale;
rb.y *= fScale;
// undo offset to bottom right corner after transformation
rb -= BPoint(1.0, 1.0);
// fBaseRenderer->add_clip_box(floorf(lt.x),
// floorf(lt.y),
// ceilf(rb.x),
@ -927,7 +922,128 @@ Painter::_DrawPolygon(const BPoint* ptArray, int32 numPts,
}
}
// _DrawBitmap
void
Painter::_DrawBitmap(const agg::rendering_buffer& srcBuffer, color_space format,
BRect actualBitmapRect, BRect bitmapRect, BRect viewRect) const
{
switch (format) {
case B_RGB32:
case B_RGBA32:
_DrawBitmap32(srcBuffer, actualBitmapRect, bitmapRect, viewRect);
break;
default:
fprintf(stderr, "Painter::DrawBitmap() - unsupported colorspace: %d\n", format);
break;
}
}
// _DrawBitmap32
void
Painter::_DrawBitmap32(const agg::rendering_buffer& srcBuffer,
BRect actualBitmapRect, BRect bitmapRect, BRect viewRect) const
{
typedef agg::span_allocator<agg::rgba8> span_alloc_type;
typedef agg::span_interpolator_linear<> interpolator_type;
typedef agg::span_image_filter_rgba32_nn<agg::order_bgra32,
interpolator_type> span_gen_type;
typedef agg::renderer_scanline_aa<renderer_base, span_gen_type> image_renderer_type;
if (bitmapRect.IsValid() && bitmapRect.Intersects(actualBitmapRect)
&& viewRect.IsValid()) {
// compensate for the lefttop offset the actualBitmapRect might have
// NOTE: I have no clue why enabling the next call gives a wrong result!
// According to the BeBook, bitmapRect is supposed to be in native
// bitmap space!
// bitmapRect.OffsetBy(-actualBitmapRect.left, -actualBitmapRect.top);
actualBitmapRect.OffsetBy(-actualBitmapRect.left, -actualBitmapRect.top);
// calculate the scaling
double xScale = (viewRect.Width() + 1) / (bitmapRect.Width() + 1);
double yScale = (viewRect.Height() + 1) / (bitmapRect.Height() + 1);
// constrain rect to passed bitmap bounds
// and transfer the changes to the viewRect
if (bitmapRect.left < actualBitmapRect.left) {
float diff = actualBitmapRect.left - bitmapRect.left;
viewRect.left += diff * xScale;
bitmapRect.left = actualBitmapRect.left;
}
if (bitmapRect.top < actualBitmapRect.top) {
float diff = actualBitmapRect.top - bitmapRect.top;
viewRect.top += diff;
bitmapRect.top = actualBitmapRect.top;
}
if (bitmapRect.right > actualBitmapRect.right) {
float diff = bitmapRect.right - actualBitmapRect.right;
viewRect.right -= diff;
bitmapRect.right = actualBitmapRect.right;
}
if (bitmapRect.bottom > actualBitmapRect.bottom) {
float diff = bitmapRect.right - actualBitmapRect.bottom;
viewRect.bottom -= diff;
bitmapRect.bottom = actualBitmapRect.bottom;
}
float xOffset = viewRect.left - (bitmapRect.left * xScale);
float yOffset = viewRect.top - (bitmapRect.top * yScale);
agg::trans_affine srcMatrix;
// srcMatrix *= agg::trans_affine_translation(-actualBitmapRect.left, -actualBitmapRect.top);
srcMatrix *= agg::trans_affine_scaling(fScale, fScale);
srcMatrix *= agg::trans_affine_translation(fOrigin.x, fOrigin.y);
agg::trans_affine imgMatrix;
imgMatrix *= agg::trans_affine_scaling(xScale, yScale);
imgMatrix *= agg::trans_affine_translation(xOffset, yOffset);
imgMatrix *= agg::trans_affine_scaling(fScale, fScale);
imgMatrix *= agg::trans_affine_translation(fOrigin.x, fOrigin.y);
imgMatrix.invert();
span_alloc_type sa;
interpolator_type interpolator(imgMatrix);
span_gen_type sg(sa, srcBuffer, agg::rgba(0, 0, 0, 0), interpolator);
image_renderer_type ri(*fBaseRenderer, sg);
agg::rasterizer_scanline_aa<> pf;
agg::scanline_u8 sl;
// path encloses image
agg::path_storage path;
path.move_to(viewRect.left, viewRect.top);
path.line_to(viewRect.right + 1, viewRect.top);
path.line_to(viewRect.right + 1, viewRect.bottom + 1);
path.line_to(viewRect.left, viewRect.bottom + 1);
path.close_polygon();
agg::conv_transform<agg::path_storage> tr(path, srcMatrix);
pf.add_path(tr);
agg::render_scanlines(pf, sl, ri);
}
}
// _InvertRect32
void
Painter::_InvertRect32(BRect r) const
{
if (fBuffer) {
int32 width = r.IntegerWidth() + 1;
for (int32 y = (int32)r.top; y <= (int32)r.bottom; y++) {
uint8* dst = fBuffer->row(y);
dst += (int32)r.left * 4;
for (int32 i = 0; i < width; i++) {
dst[0] = 255 - dst[0];
dst[1] = 255 - dst[1];
dst[2] = 255 - dst[2];
dst += 4;
}
}
}
}
// #pragma mark -