first simplistic implementation of drag bitmaps, drawing modes need more work, drawing text into offscreen bitmaps seems to be broken for some weird reason, B_OP_COPY actually copies the alpha value of the color as well

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15671 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2005-12-25 22:17:17 +00:00
parent 5a077d3f0d
commit 9d909e2556
22 changed files with 266 additions and 40 deletions
+6
View File
@@ -1335,6 +1335,12 @@ BView::DragMessage(BMessage *message, BBitmap *image,
fOwner->fLink->Attach<BPoint>(offset);
fOwner->fLink->Attach<int32>(bufferSize);
fOwner->fLink->Attach(buffer, bufferSize);
// we need to wait for the server
// to actually process this message
// before we can delete the bitmap
int32 code;
fOwner->fLink->FlushWithReply(code);
delete [] buffer;
} else {
+2
View File
@@ -612,6 +612,8 @@ printf(" sending message to previous mouse target\n");
fDragMessage.MakeEmpty();
fDragMessage.what = 0;
fDraggingMessage = false;
fHWInterface->SetDragBitmap(NULL, B_ORIGIN);
}
+6
View File
@@ -1710,9 +1710,15 @@ ServerWindow::_DispatchViewMessage(int32 code,
&& dragMessage.Unflatten(buffer) == B_OK) {
// ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken);
fDesktop->EventDispatcher().SetDragMessage(dragMessage/*, bitmap*/);
if (ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken)) {
fDesktop->HWInterface()->SetDragBitmap(bitmap, offset);
}
}
delete[] buffer;
}
// sync the client (it can now delete the bitmap)
fLink.StartMessage(B_OK);
fLink.Flush();
break;
}
+204 -22
View File
@@ -15,6 +15,9 @@ HWInterface::HWInterface(bool doubleBuffered)
: MultiLocker("hw interface lock"),
fCursorAreaBackup(NULL),
fCursor(NULL),
fDragBitmap(NULL),
fDragBitmapOffset(0, 0),
fCursorAndDragBitmap(NULL),
fCursorVisible(false),
fCursorLocation(0, 0),
fDoubleBuffered(doubleBuffered),
@@ -28,6 +31,7 @@ HWInterface::~HWInterface()
{
delete fCursorAreaBackup;
delete fCursor;
delete fCursorAndDragBitmap;
delete fUpdateExecutor;
}
@@ -58,20 +62,25 @@ void
HWInterface::SetCursor(ServerCursor* cursor)
{
if (WriteLock()) {
if (fDragBitmap) {
// if a bitmap is being dragged,
// we don't currently allow changing
// the cursor, part of the reason being
// that the original drag bitmap is not
// around anymore... but it could be
// considered iritating to the user to
// change cursor shapes while something
// is dragged anyways.
WriteUnlock();
return;
}
if (fCursor != cursor) {
BRect oldFrame = _CursorFrame();
delete fCursor;
delete fCursorAreaBackup;
fCursor = cursor;
Invalidate(oldFrame);
BRect r = _CursorFrame();
if (fCursor && !IsDoubleBuffered()) {
BRect cursorBounds = fCursor->Bounds();
fCursorAreaBackup = new buffer_clip(cursorBounds.IntegerWidth() + 1,
cursorBounds.IntegerHeight() + 1);
_DrawCursor(r);
} else
fCursorAreaBackup = NULL;
_AdoptDragBitmap(fDragBitmap, fDragBitmapOffset);
Invalidate(r);
}
WriteUnlock();
@@ -142,6 +151,17 @@ HWInterface::GetCursorPosition()
return location;
}
// SetDragBitmap
void
HWInterface::SetDragBitmap(const ServerBitmap* bitmap,
const BPoint& offsetFromCursor)
{
if (WriteLock()) {
_AdoptDragBitmap(bitmap, offsetFromCursor);
WriteUnlock();
}
}
// DrawingBuffer
RenderingBuffer*
HWInterface::DrawingBuffer() const
@@ -294,8 +314,8 @@ HWInterface::_DrawCursor(BRect area) const
src += top * srcBPR + left * 4;
// offset into cursor bitmap
uint8* crs = (uint8*)fCursor->Bits();
uint32 crsBPR = fCursor->BytesPerRow();
uint8* crs = (uint8*)fCursorAndDragBitmap->Bits();
uint32 crsBPR = fCursorAndDragBitmap->BytesPerRow();
// since area is clipped to cf,
// the diff between top and cf.top is always positive,
// same for diff between left and cf.left
@@ -320,13 +340,15 @@ HWInterface::_DrawCursor(BRect area) const
uint8* c = crs;
uint8* d = dst;
uint8* b = bup;
for (int32 x = left; x <= right; x++) {
*(uint32*)b = *(uint32*)s;
// assumes backbuffer alpha = 255
uint8 a = c[3];
d[0] = (((c[0] - b[0]) * a) + (b[0] << 8)) >> 8;
d[1] = (((c[1] - b[1]) * a) + (b[1] << 8)) >> 8;
d[2] = (((c[2] - b[2]) * a) + (b[2] << 8)) >> 8;
// assuming pre-multiplied cursor bitmap
uint8 a = 255 - c[3];
d[0] = ((b[0] * a) >> 8) + c[0];
d[1] = ((b[1] * a) >> 8) + c[1];
d[2] = ((b[2] * a) >> 8) + c[2];
s += 4;
c += 4;
d += 4;
@@ -345,10 +367,11 @@ HWInterface::_DrawCursor(BRect area) const
uint8* d = dst;
for (int32 x = left; x <= right; x++) {
// assumes backbuffer alpha = 255
uint8 a = c[3];
d[0] = (((c[0] - s[0]) * a) + (s[0] << 8)) >> 8;
d[1] = (((c[1] - s[1]) * a) + (s[1] << 8)) >> 8;
d[2] = (((c[2] - s[2]) * a) + (s[2] << 8)) >> 8;
// assuming pre-multiplied cursor bitmap
uint8 a = 255 - c[3];
d[0] = ((s[0] * a) >> 8) + c[0];
d[1] = ((s[1] * a) >> 8) + c[1];
d[2] = ((s[2] * a) >> 8) + c[2];
s += 4;
c += 4;
d += 4;
@@ -358,7 +381,6 @@ HWInterface::_DrawCursor(BRect area) const
dst += width * 4;
}
}
// copy result to front buffer
_CopyToFront(buffer, width * 4, left, top, right, bottom);
@@ -601,9 +623,9 @@ BRect
HWInterface::_CursorFrame() const
{
BRect frame(0.0, 0.0, -1.0, -1.0);
if (fCursor && fCursorVisible) {
frame = fCursor->Bounds();
frame.OffsetTo(fCursorLocation - fCursor->GetHotSpot());
if (fCursorAndDragBitmap && fCursorVisible) {
frame = fCursorAndDragBitmap->Bounds();
frame.OffsetTo(fCursorLocation - fCursorAndDragBitmap->GetHotSpot());
}
return frame;
}
@@ -624,5 +646,165 @@ HWInterface::_RestoreCursorArea() const
}
}
// _AdoptDragBitmap
void
HWInterface::_AdoptDragBitmap(const ServerBitmap* bitmap, const BPoint& offset)
{
// TODO: support other colorspaces/convert bitmap
if (bitmap && (bitmap->ColorSpace() != B_RGB32 && bitmap->ColorSpace() != B_RGBA32)) {
fprintf(stderr, "HWInterface::_AdoptDragBitmap() - bitmap has yet unsupported colorspace\n");
return;
}
_RestoreCursorArea();
if (fCursorAndDragBitmap != fCursor) {
delete fCursorAndDragBitmap;
fCursorAndDragBitmap = NULL;
}
if (bitmap) {
BRect bitmapFrame = bitmap->Bounds();
if (fCursor) {
// put bitmap frame and cursor frame into the same
// coordinate space (the cursor location is the origin)
bitmapFrame.OffsetTo(BPoint(-offset.x, -offset.y));
BRect cursorFrame(fCursor->Bounds());
BPoint hotspot(fCursor->GetHotSpot());
// the hotspot is at the origin
cursorFrame.OffsetTo(-hotspot.x, -hotspot.y);
BRect combindedBounds = bitmapFrame | cursorFrame;
BPoint shift;
shift.x = -combindedBounds.left;
shift.y = -combindedBounds.top;
combindedBounds.OffsetBy(shift);
cursorFrame.OffsetBy(shift);
bitmapFrame.OffsetBy(shift);
fCursorAndDragBitmap = new ServerCursor(combindedBounds,
bitmap->ColorSpace(), 0,
hotspot + shift);
// clear the combined buffer
uint8* dst = (uint8*)fCursorAndDragBitmap->Bits();
uint32 dstBPR = fCursorAndDragBitmap->BytesPerRow();
memset(dst, 0, fCursorAndDragBitmap->BitsLength());
// put drag bitmap into combined buffer
uint8* src = (uint8*)bitmap->Bits();
uint32 srcBPR = bitmap->BytesPerRow();
dst += (int32)bitmapFrame.top * dstBPR + (int32)bitmapFrame.left * 4;
uint32 width = bitmapFrame.IntegerWidth() + 1;
uint32 height = bitmapFrame.IntegerHeight() + 1;
for (uint32 y = 0; y < height; y++) {
memcpy(dst, src, srcBPR);
dst += dstBPR;
src += srcBPR;
}
// compose cursor into combined buffer
dst = (uint8*)fCursorAndDragBitmap->Bits();
dst += (int32)cursorFrame.top * dstBPR + (int32)cursorFrame.left * 4;
src = (uint8*)fCursor->Bits();
srcBPR = fCursor->BytesPerRow();
width = cursorFrame.IntegerWidth() + 1;
height = cursorFrame.IntegerHeight() + 1;
for (uint32 y = 0; y < height; y++) {
uint8* d = dst;
uint8* s = src;
for (uint32 x = 0; x < width; x++) {
// takes two semi-transparent pixels
// with unassociated alpha (not pre-multiplied)
// and produces a premultiplied
if (s[3] > 0) {
if (s[3] == 255) {
d[0] = s[0];
d[1] = s[1];
d[2] = s[2];
d[3] = 255;
} else {
uint8 alphaRest = 255 - s[3];
uint32 alphaTemp = (65025 - alphaRest * (255 - d[3]));
uint32 alphaDest = d[3] * alphaRest;
uint32 alphaSrc = 255 * s[3];
d[0] = (d[0] * alphaDest + s[0] * alphaSrc) / alphaTemp;
d[1] = (d[1] * alphaDest + s[1] * alphaSrc) / alphaTemp;
d[2] = (d[2] * alphaDest + s[2] * alphaSrc) / alphaTemp;
d[3] = alphaTemp / 255;
}
}
// TODO: make sure the alpha is always upside down,
// then it doesn't need to be done when drawing the cursor
// (see _DrawCursor())
// d[3] = 255 - d[3];
d += 4;
s += 4;
}
dst += dstBPR;
src += srcBPR;
}
// handle pre-multiplication with alpha
// for faster compositing during cursor drawing
width = combindedBounds.IntegerWidth() + 1;
height = combindedBounds.IntegerHeight() + 1;
dst = (uint8*)fCursorAndDragBitmap->Bits();
for (uint32 y = 0; y < height; y++) {
uint8* d = dst;
for (uint32 x = 0; x < width; x++) {
d[0] = (d[0] * d[3]) >> 8;
d[1] = (d[1] * d[3]) >> 8;
d[2] = (d[2] * d[3]) >> 8;
d += 4;
}
dst += dstBPR;
}
} else {
fCursorAndDragBitmap = new ServerCursor(bitmap->Bits(),
bitmapFrame.IntegerWidth() + 1,
bitmapFrame.IntegerHeight() + 1,
bitmap->ColorSpace());
fCursorAndDragBitmap->SetHotSpot(BPoint(-offset.x, -offset.y));
}
} else {
fCursorAndDragBitmap = fCursor;
}
// TODO: handle reference counting stuff
// if (fDragBitmap)
// fDragBitmap->Release();
fDragBitmap = bitmap;
fDragBitmapOffset = offset;
// if (fDragBitmap)
// fDragBitmap->Aquire();
delete fCursorAreaBackup;
fCursorAreaBackup = NULL;
if (!fCursorAndDragBitmap)
return;
if (fCursorAndDragBitmap && !IsDoubleBuffered()) {
BRect cursorBounds = fCursorAndDragBitmap->Bounds();
fCursorAreaBackup = new buffer_clip(cursorBounds.IntegerWidth() + 1,
cursorBounds.IntegerHeight() + 1);
}
_DrawCursor(_CursorFrame());
}
+9
View File
@@ -17,6 +17,7 @@
class RenderingBuffer;
class RGBColor;
class ServerBitmap;
class ServerCursor;
class UpdateQueue;
class BString;
@@ -82,6 +83,9 @@ class HWInterface : public MultiLocker {
const float& y);
BPoint GetCursorPosition();
void SetDragBitmap(const ServerBitmap* bitmap,
const BPoint& offsetFromCursor);
// frame buffer access (you need to ReadLock!)
RenderingBuffer* DrawingBuffer() const;
virtual RenderingBuffer* FrontBuffer() const = 0;
@@ -123,6 +127,8 @@ class HWInterface : public MultiLocker {
BRect _CursorFrame() const;
void _RestoreCursorArea() const;
void _AdoptDragBitmap(const ServerBitmap* bitmap,
const BPoint& offset);
// If we draw the cursor somewhere in the drawing buffer,
// we need to backup its contents before drawing, so that
@@ -158,6 +164,9 @@ class HWInterface : public MultiLocker {
buffer_clip* fCursorAreaBackup;
ServerCursor* fCursor;
const ServerBitmap* fDragBitmap;
BPoint fDragBitmapOffset;
ServerCursor* fCursorAndDragBitmap;
bool fCursorVisible;
BPoint fCursorLocation;
bool fDoubleBuffered;
+11 -7
View File
@@ -380,7 +380,6 @@ Painter::StraightLine(BPoint a, BPoint b, const rgb_color& c) const
} else if (a.y == b.y) {
// horizontal
uint32 bpr = fBuffer->stride();
int32 y = (int32)a.y;
uint8* dst = fBuffer->row(y);
int32 x1 = (int32)min_c(a.x, b.x);
@@ -699,7 +698,7 @@ Painter::FillRect(const BRect& r, const rgb_color& c) const
color.data8[0] = c.blue;
color.data8[1] = c.green;
color.data8[2] = c.red;
color.data8[3] = 255;
color.data8[3] = c.alpha;
// fill rects, iterate over clipping boxes
fBaseRenderer->first_clip_box();
do {
@@ -1106,25 +1105,30 @@ Painter::_SetRendererColor(const rgb_color& color) const
#if ALIASED_DRAWING
fOutlineRenderer->line_color(agg::rgba(color.red / 255.0,
color.green / 255.0,
color.blue / 255.0));
color.blue / 255.0,
color.alpha / 255.0));
#else
fOutlineRenderer->color(agg::rgba(color.red / 255.0,
color.green / 255.0,
color.blue / 255.0));
color.blue / 255.0,
color.alpha / 255.0));
#endif // ALIASED_DRAWING
#endif // USE_OUTLINE_RASTERIZER
if (fRenderer)
fRenderer->color(agg::rgba(color.red / 255.0,
color.green / 255.0,
color.blue / 255.0));
color.blue / 255.0,
color.alpha / 255.0));
if (fFontRendererSolid)
fFontRendererSolid->color(agg::rgba(color.red / 255.0,
color.green / 255.0,
color.blue / 255.0));
color.blue / 255.0,
color.alpha / 255.0));
if (fFontRendererBin)
fFontRendererBin->color(agg::rgba(color.red / 255.0,
color.green / 255.0,
color.blue / 255.0));
color.blue / 255.0,
color.alpha / 255.0));
}
@@ -34,6 +34,7 @@ union pixel32 {
d[0] = (((((b) - _p.data8[0]) * (a)) + (_p.data8[0] << 8)) >> 8); \
d[1] = (((((g) - _p.data8[1]) * (a)) + (_p.data8[1] << 8)) >> 8); \
d[2] = (((((r) - _p.data8[2]) * (a)) + (_p.data8[2] << 8)) >> 8); \
d[3] = 255; \
}
// BLEND_FROM
@@ -48,6 +49,7 @@ union pixel32 {
d[0] = (((((b2) - (b1)) * (a)) + ((b1) << 8)) >> 8); \
d[1] = (((((g2) - (g1)) * (a)) + ((g1) << 8)) >> 8); \
d[2] = (((((r2) - (r1)) * (a)) + ((r1) << 8)) >> 8); \
d[3] = 255; \
}
// BLEND16
@@ -63,6 +65,7 @@ union pixel32 {
d[0] = (((((b) - _p.data8[0]) * (a)) + (_p.data8[0] << 16)) >> 16); \
d[1] = (((((g) - _p.data8[1]) * (a)) + (_p.data8[1] << 16)) >> 16); \
d[2] = (((((r) - _p.data8[2]) * (a)) + (_p.data8[2] << 16)) >> 16); \
d[3] = 255; \
}
@@ -31,6 +31,7 @@
d[0] = min_c(255, _p.data8[0] + (b)); \
d[1] = min_c(255, _p.data8[1] + (g)); \
d[2] = min_c(255, _p.data8[2] + (r)); \
d[3] = 255; \
}
@@ -23,6 +23,7 @@
d[0] = (r); \
d[1] = (g); \
d[2] = (b); \
d[3] = 255; \
}
// blend_pixel_alpha_cc
@@ -23,6 +23,7 @@
d[0] = (b); \
d[1] = (g); \
d[2] = (r); \
d[3] = 255; \
}
// blend_pixel_alpha_co
@@ -23,6 +23,7 @@
d[0] = (b); \
d[1] = (g); \
d[2] = (r); \
d[3] = 255; \
}
// blend_pixel_alpha_pc
@@ -23,6 +23,7 @@
d[0] = (b); \
d[1] = (g); \
d[2] = (r); \
d[3] = 255; \
}
// blend_pixel_alpha_po
@@ -30,6 +30,7 @@
d[0] = (_p.data8[0] + (b)) >> 1; \
d[1] = (_p.data8[1] + (g)) >> 1; \
d[2] = (_p.data8[2] + (r)) >> 1; \
d[3] = 255; \
}
// blend_pixel_blend
@@ -18,11 +18,12 @@
}
// ASSIGN_COPY
#define ASSIGN_COPY(d, r, g, b) \
#define ASSIGN_COPY(d, r, g, b, a) \
{ \
d[0] = (b); \
d[1] = (g); \
d[2] = (r); \
d[3] = (a); \
}
@@ -34,7 +35,7 @@ blend_pixel_copy(int x, int y, const color_type& c, uint8 cover,
uint8* p = buffer->row(y) + (x << 2);
rgb_color color = pattern->R5ColorAt(x, y);
if (cover == 255) {
ASSIGN_COPY(p, color.red, color.green, color.blue);
ASSIGN_COPY(p, color.red, color.green, color.blue, color.alpha);
} else {
rgb_color l = pattern->LowColor().GetColor32();
BLEND_COPY(p, color.red, color.green, color.blue, cover,
@@ -101,7 +102,7 @@ blend_solid_hspan_copy(int x, int y, unsigned len,
rgb_color color = pattern->R5ColorAt(x, y);
if (*covers) {
if (*covers == 255) {
ASSIGN_COPY(p, color.red, color.green, color.blue);
ASSIGN_COPY(p, color.red, color.green, color.blue, color.alpha);
} else {
BLEND_COPY(p, color.red, color.green, color.blue, *covers,
l.red, l.green, l.blue);
@@ -127,7 +128,7 @@ blend_solid_vspan_copy(int x, int y, unsigned len,
rgb_color color = pattern->R5ColorAt(x, y);
if (*covers) {
if (*covers == 255) {
ASSIGN_COPY(p, color.red, color.green, color.blue);
ASSIGN_COPY(p, color.red, color.green, color.blue, color.alpha);
} else {
BLEND_COPY(p, color.red, color.green, color.blue, *covers,
l.red, l.green, l.blue);
@@ -153,7 +154,7 @@ blend_color_hspan_copy(int x, int y, unsigned len, const color_type* colors,
do {
if(*covers) {
if(*covers == 255) {
ASSIGN_COPY(p, colors->r, colors->g, colors->b);
ASSIGN_COPY(p, colors->r, colors->g, colors->b, colors->a);
} else {
BLEND_COPY(p, colors->r, colors->g, colors->b, *covers,
l.red, l.green, l.blue);
@@ -167,7 +168,7 @@ blend_color_hspan_copy(int x, int y, unsigned len, const color_type* colors,
// solid full opcacity
if (cover == 255) {
do {
ASSIGN_COPY(p, colors->r, colors->g, colors->b);
ASSIGN_COPY(p, colors->r, colors->g, colors->b, colors->a);
p += 4;
++colors;
} while(--len);
@@ -18,7 +18,7 @@ blend_pixel_copy_solid(int x, int y, const color_type& c, uint8 cover,
{
uint8* p = buffer->row(y) + (x << 2);
if (cover == 255) {
ASSIGN_COPY(p, c.r, c.g, c.b);
ASSIGN_COPY(p, c.r, c.g, c.b, c.a);
} else {
rgb_color l = pattern->LowColor().GetColor32();
BLEND_COPY(p, c.r, c.g, c.b, cover,
@@ -69,7 +69,7 @@ blend_solid_hspan_copy_solid(int x, int y, unsigned len,
do {
if (*covers) {
if(*covers == 255) {
ASSIGN_COPY(p, c.r, c.g, c.b);
ASSIGN_COPY(p, c.r, c.g, c.b, c.a);
} else {
BLEND_COPY(p, c.r, c.g, c.b, *covers,
l.red, l.green, l.blue);
@@ -94,7 +94,7 @@ blend_solid_vspan_copy_solid(int x, int y, unsigned len,
do {
if (*covers) {
if (*covers == 255) {
ASSIGN_COPY(p, c.r, c.g, c.b);
ASSIGN_COPY(p, c.r, c.g, c.b, c.a);
} else {
BLEND_COPY(p, c.r, c.g, c.b, *covers,
l.red, l.green, l.blue);
@@ -121,7 +121,7 @@ blend_color_hspan_copy_solid(int x, int y, unsigned len,
do {
if(*covers) {
if(*covers == 255) {
ASSIGN_COPY(p, colors->r, colors->g, colors->b);
ASSIGN_COPY(p, colors->r, colors->g, colors->b, colors->a);
} else {
BLEND_COPY(p, colors->r, colors->g, colors->b, *covers,
l.red, l.green, l.blue);
@@ -135,7 +135,7 @@ blend_color_hspan_copy_solid(int x, int y, unsigned len,
// solid full opcacity
if (cover == 255) {
do {
ASSIGN_COPY(p, colors->r, colors->g, colors->b);
ASSIGN_COPY(p, colors->r, colors->g, colors->b, colors->a);
p += 4;
++colors;
} while(--len);
@@ -23,6 +23,7 @@
d[0] = (b); \
d[1] = (g); \
d[2] = (r); \
d[3] = 255; \
}
// blend_pixel_erase
@@ -27,6 +27,7 @@
d[0] = 255 - _p.data8[0]; \
d[1] = 255 - _p.data8[1]; \
d[2] = 255 - _p.data8[2]; \
d[3] = 255; \
}
// blend_pixel_invert
@@ -31,6 +31,7 @@
d[0] = max_c(_p.data8[0], (b)); \
d[1] = max_c(_p.data8[1], (g)); \
d[2] = max_c(_p.data8[2], (r)); \
d[3] = 255; \
}
@@ -25,6 +25,7 @@
d[0] = min_c(_p.data8[0], (b)); \
d[1] = min_c(_p.data8[1], (g)); \
d[2] = min_c(_p.data8[2], (r)); \
d[3] = 255; \
}
@@ -23,6 +23,7 @@
d[0] = (b); \
d[1] = (g); \
d[2] = (r); \
d[3] = 255; \
}
// blend_pixel_over
@@ -23,6 +23,7 @@
d[0] = (b); \
d[1] = (g); \
d[2] = (r); \
d[3] = 255; \
}
// compare
@@ -33,6 +33,7 @@
d[0] = max_c(0, _p.data8[0] - (b)); \
d[1] = max_c(0, _p.data8[1] - (g)); \
d[2] = max_c(0, _p.data8[2] - (r)); \
d[3] = 255; \
}