app_server: Implement more composition modes

* Use agg::comp_op classes to blend pixels.
* Subpixel path not implemented.
* Needed by WebKit.
* Implements #10274.

Change-Id: I07b0002196fd0a05fc100bd9f6d703c33cadc85b
Reviewed-on: https://review.haiku-os.org/c/haiku/+/2932
Reviewed-by: X512 <danger_mail@list.ru>
Reviewed-by: Adrien Destugues <pulkomandy@gmail.com>
This commit is contained in:
Kacper Kasper 2020-06-19 21:35:48 +02:00 committed by waddlesplash
parent cc30c791bd
commit 97bd6fe8d4
23 changed files with 563 additions and 15 deletions

View File

@ -111,3 +111,204 @@
\since BeOS R3
*/
/*!
\var alpha_function B_ALPHA_COMPOSITE_SOURCE_OVER
Draws source over destination preserving transparency. Same as
\c B_ALPHA_COMPOSITE.
\image{inline} html B_ALPHA_COMPOSITE_SOURCE.png "Source"
->
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION.png "Destination"
=
\image{inline} html B_ALPHA_COMPOSITE_SOURCE_OVER.png "Result"
\since Haiku R1
*/
/*!
\var alpha_function B_ALPHA_COMPOSITE_SOURCE_IN
Draws source only where destination is not transparent.
\image{inline} html B_ALPHA_COMPOSITE_SOURCE.png "Source"
->
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION.png "Destination"
=
\image{inline} html B_ALPHA_COMPOSITE_SOURCE_IN.png "Result"
\since Haiku R1
*/
/*!
\var alpha_function B_ALPHA_COMPOSITE_SOURCE_OUT
Draws source only where destination is transparent.
\image{inline} html B_ALPHA_COMPOSITE_SOURCE.png "Source"
->
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION.png "Destination"
=
\image{inline} html B_ALPHA_COMPOSITE_SOURCE_OUT.png "Result"
\since Haiku R1
*/
/*!
\var alpha_function B_ALPHA_COMPOSITE_SOURCE_ATOP
Draws source only where destination is not transparent. Colors from both
are used in the result.
\image{inline} html B_ALPHA_COMPOSITE_SOURCE.png "Source"
->
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION.png "Destination"
=
\image{inline} html B_ALPHA_COMPOSITE_SOURCE_ATOP.png "Result"
\since Haiku R1
*/
/*!
\var alpha_function B_ALPHA_COMPOSITE_DESTINATION_OVER
Draws source where destination is transparent, making it appear as if it
is drawn behind.
\image{inline} html B_ALPHA_COMPOSITE_SOURCE.png "Source"
->
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION.png "Destination"
=
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION_OVER.png "Result"
\since Haiku R1
*/
/*!
\var alpha_function B_ALPHA_COMPOSITE_DESTINATION_IN
Blends source alpha channel with destination.
\image{inline} html B_ALPHA_COMPOSITE_SOURCE.png "Source"
->
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION.png "Destination"
=
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION_IN.png "Result"
\since Haiku R1
*/
/*!
\var alpha_function B_ALPHA_COMPOSITE_DESTINATION_OUT
Blends inverse of source alpha channel with destination. Result appears as
if source was cut out of destination.
\image{inline} html B_ALPHA_COMPOSITE_SOURCE.png "Source"
->
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION.png "Destination"
=
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION_OUT.png "Result"
\since Haiku R1
*/
/*!
\var alpha_function B_ALPHA_COMPOSITE_DESTINATION_ATOP
Draws source only where it is not transparent. Destination is blended on
top of it. Colors from both are used in the result.
\image{inline} html B_ALPHA_COMPOSITE_SOURCE.png "Source"
->
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION.png "Destination"
=
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION_ATOP.png "Result"
\since Haiku R1
*/
/*!
\var alpha_function B_ALPHA_COMPOSITE_XOR
Result is transparent only where both source and destination are transparent
or opaque.
\image{inline} html B_ALPHA_COMPOSITE_SOURCE.png "Source"
->
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION.png "Destination"
=
\image{inline} html B_ALPHA_COMPOSITE_XOR.png "Result"
\since Haiku R1
*/
/*!
\var alpha_function B_ALPHA_COMPOSITE_CLEAR
Erases destination to full transparency, regardless of source alpha value.
\image{inline} html B_ALPHA_COMPOSITE_SOURCE.png "Source"
->
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION.png "Destination"
=
\image{inline} html B_ALPHA_COMPOSITE_CLEAR.png "Result"
\since Haiku R1
*/
/*!
\var alpha_function B_ALPHA_COMPOSITE_DIFFERENCE
Subtracts both inputs in a way that always yields positive result.
\image{inline} html B_ALPHA_COMPOSITE_SOURCE.png "Source"
->
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION.png "Destination"
=
\image{inline} html B_ALPHA_COMPOSITE_DIFFERENCE.png "Result"
\since Haiku R1
*/
/*!
\var alpha_function B_ALPHA_COMPOSITE_LIGHTEN
Retains lighter pixels of both inputs.
\image{inline} html B_ALPHA_COMPOSITE_SOURCE.png "Source"
->
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION.png "Destination"
=
\image{inline} html B_ALPHA_COMPOSITE_LIGHTEN.png "Result"
\since Haiku R1
*/
/*!
\var alpha_function B_ALPHA_COMPOSITE_DARKEN
Retains darker pixels of both inputs.
\image{inline} html B_ALPHA_COMPOSITE_SOURCE.png "Source"
->
\image{inline} html B_ALPHA_COMPOSITE_DESTINATION.png "Destination"
=
\image{inline} html B_ALPHA_COMPOSITE_DARKEN.png "Result"
\since Haiku R1
*/

View File

@ -2124,9 +2124,11 @@ SetViewColor(Parent()->ViewColor());
\param alphaFunc Set to one of the following:
- \c B_ALPHA_OVERLAY Used for drawing a image with transparency over an opaque
background.
- \c B_ALPHA_COMPOSITE Used to composite two or more transparent images
- \c B_ALPHA_COMPOSITE_* Used to composite two or more transparent images
together offscreen to produce a new image drawn using
\c B_ALPHA_OVERLAY mode.
\c B_ALPHA_OVERLAY mode.
\note Modes other than \c B_ALPHA_OVERLAY and \c B_ALPHA_COMPOSITE work
only with \c B_PIXEL_ALPHA.
\since BeOS R5
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

View File

@ -298,7 +298,20 @@ enum source_alpha {
enum alpha_function {
B_ALPHA_OVERLAY = 0,
B_ALPHA_COMPOSITE
B_ALPHA_COMPOSITE,
B_ALPHA_COMPOSITE_SOURCE_OVER = B_ALPHA_COMPOSITE,
B_ALPHA_COMPOSITE_SOURCE_IN,
B_ALPHA_COMPOSITE_SOURCE_OUT,
B_ALPHA_COMPOSITE_SOURCE_ATOP,
B_ALPHA_COMPOSITE_DESTINATION_OVER,
B_ALPHA_COMPOSITE_DESTINATION_IN,
B_ALPHA_COMPOSITE_DESTINATION_OUT,
B_ALPHA_COMPOSITE_DESTINATION_ATOP,
B_ALPHA_COMPOSITE_XOR,
B_ALPHA_COMPOSITE_CLEAR,
B_ALPHA_COMPOSITE_DIFFERENCE,
B_ALPHA_COMPOSITE_LIGHTEN,
B_ALPHA_COMPOSITE_DARKEN
};

View File

@ -0,0 +1,119 @@
/*
* Copyright 2020, Kacper Kasper <kacperkasper@gmail.com>
* All rights reserved. Distributed under the terms of the MIT license.
*
* Copyright 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
*/
#ifndef AGG_COMP_OP_ADAPTER_H
#define AGG_COMP_OP_ADAPTER_H
#include <stdio.h>
#include <agg_pixfmt_rgba.h>
#include "PatternHandler.h"
template<typename CompOp, typename RenBuf>
struct AggCompOpAdapter {
typedef typename CompOp::color_type color_type;
typedef typename CompOp::color_type::value_type value_type;
static void
blend_pixel(int x, int y,
const color_type& c,
uint8 cover, RenBuf* buffer,
const PatternHandler* pattern)
{
value_type* p = buffer->row_ptr(y) + x * sizeof(color_type);
rgb_color color = pattern->ColorAt(x, y);
CompOp::blend_pix(p,
color.red, color.green, color.blue, color.alpha, cover);
}
static void
blend_hline(int x, int y,
unsigned len,
const color_type& c,
uint8 cover, RenBuf* buffer,
const PatternHandler* pattern)
{
value_type* p = buffer->row_ptr(y) + x * sizeof(color_type);
do {
rgb_color color = pattern->ColorAt(x, y);
CompOp::blend_pix(p,
color.red, color.green, color.blue, color.alpha, cover);
x++;
p += sizeof(color_type) / sizeof(value_type);
} while(--len);
}
static void
blend_solid_hspan(int x, int y,
unsigned len,
const color_type& c,
const uint8* covers, RenBuf* buffer,
const PatternHandler* pattern)
{
value_type* p = buffer->row_ptr(y) + x * sizeof(color_type);
do {
rgb_color color = pattern->ColorAt(x, y);
CompOp::blend_pix(p,
color.red, color.green, color.blue, color.alpha, *covers);
covers++;
p += sizeof(color_type) / sizeof(value_type);
x++;
} while(--len);
}
static void
blend_solid_hspan_subpix(int x, int y,
unsigned len,
const color_type& c,
const uint8* covers, RenBuf* buffer,
const PatternHandler* pattern)
{
fprintf(stderr,
"B_ALPHA_COMPOSITE_* subpixel drawing not implemented\n");
}
static void
blend_solid_vspan(int x, int y,
unsigned len,
const color_type& c,
const uint8* covers, RenBuf* buffer,
const PatternHandler* pattern)
{
value_type* p = buffer->row_ptr(y) + x * sizeof(color_type);
do {
rgb_color color = pattern->ColorAt(x, y);
CompOp::blend_pix(p,
color.red, color.green, color.blue, color.alpha, *covers);
covers++;
p += buffer->stride();
y++;
} while(--len);
}
static void
blend_color_hspan(int x, int y,
unsigned len,
const color_type* colors,
const uint8* covers,
uint8 cover, RenBuf* buffer,
const PatternHandler* pattern)
{
value_type* p = buffer->row_ptr(y) + x * sizeof(color_type);
do {
CompOp::blend_pix(p,
colors->r, colors->g, colors->b, colors->a,
covers ? *covers++ : cover);
p += sizeof(color_type) / sizeof(value_type);
++colors;
} while(--len);
}
};
#endif // AGG_COMP_OP_ADAPTER_H

View File

@ -328,6 +328,30 @@ PixelFormat::SetDrawingMode(drawing_mode mode, source_alpha alphaSrcMode,
fBlendSolidVSpan = blend_solid_vspan_alpha_pc;
fBlendColorHSpan = blend_color_hspan_alpha_pc;
}
} else if (alphaFncMode == B_ALPHA_COMPOSITE_SOURCE_IN) {
SetAggCompOpAdapter<alpha_src_in>();
} else if (alphaFncMode == B_ALPHA_COMPOSITE_SOURCE_OUT) {
SetAggCompOpAdapter<alpha_src_out>();
} else if (alphaFncMode == B_ALPHA_COMPOSITE_SOURCE_ATOP) {
SetAggCompOpAdapter<alpha_src_atop>();
} else if (alphaFncMode == B_ALPHA_COMPOSITE_DESTINATION_OVER) {
SetAggCompOpAdapter<alpha_dst_over>();
} else if (alphaFncMode == B_ALPHA_COMPOSITE_DESTINATION_IN) {
SetAggCompOpAdapter<alpha_dst_in>();
} else if (alphaFncMode == B_ALPHA_COMPOSITE_DESTINATION_OUT) {
SetAggCompOpAdapter<alpha_dst_out>();
} else if (alphaFncMode == B_ALPHA_COMPOSITE_DESTINATION_ATOP) {
SetAggCompOpAdapter<alpha_dst_atop>();
} else if (alphaFncMode == B_ALPHA_COMPOSITE_XOR) {
SetAggCompOpAdapter<alpha_xor>();
} else if (alphaFncMode == B_ALPHA_COMPOSITE_CLEAR) {
SetAggCompOpAdapter<alpha_clear>();
} else if (alphaFncMode == B_ALPHA_COMPOSITE_DIFFERENCE) {
SetAggCompOpAdapter<alpha_difference>();
} else if (alphaFncMode == B_ALPHA_COMPOSITE_LIGHTEN) {
SetAggCompOpAdapter<alpha_lighten>();
} else if (alphaFncMode == B_ALPHA_COMPOSITE_DARKEN) {
SetAggCompOpAdapter<alpha_darken>();
}
}
break;

View File

@ -17,9 +17,12 @@
#include <agg_basics.h>
#include <agg_color_rgba.h>
#include <agg_rendering_buffer.h>
#include <agg_pixfmt_rgba.h>
#include <GraphicsDefs.h>
#include "AggCompOpAdapter.h"
class PatternHandler;
class PixelFormat {
@ -28,6 +31,34 @@ class PixelFormat {
typedef agg::rendering_buffer agg_buffer;
typedef agg::rendering_buffer::row_data row_data;
typedef agg::order_bgra order_type;
typedef agg::comp_op_rgba_src_in<color_type, order_type> comp_src_in;
typedef agg::comp_op_rgba_src_out<color_type, order_type> comp_src_out;
typedef agg::comp_op_rgba_src_atop<color_type, order_type> comp_src_atop;
typedef agg::comp_op_rgba_dst_over<color_type, order_type> comp_dst_over;
typedef agg::comp_op_rgba_dst_in<color_type, order_type> comp_dst_in;
typedef agg::comp_op_rgba_dst_out<color_type, order_type> comp_dst_out;
typedef agg::comp_op_rgba_dst_atop<color_type, order_type> comp_dst_atop;
typedef agg::comp_op_rgba_xor<color_type, order_type> comp_xor;
typedef agg::comp_op_rgba_clear<color_type, order_type> comp_clear;
typedef agg::comp_op_rgba_difference<color_type, order_type>
comp_difference;
typedef agg::comp_op_rgba_lighten<color_type, order_type> comp_lighten;
typedef agg::comp_op_rgba_darken<color_type, order_type> comp_darken;
typedef AggCompOpAdapter<comp_src_in, agg_buffer> alpha_src_in;
typedef AggCompOpAdapter<comp_src_out, agg_buffer> alpha_src_out;
typedef AggCompOpAdapter<comp_src_atop, agg_buffer> alpha_src_atop;
typedef AggCompOpAdapter<comp_dst_over, agg_buffer> alpha_dst_over;
typedef AggCompOpAdapter<comp_dst_in, agg_buffer> alpha_dst_in;
typedef AggCompOpAdapter<comp_dst_out, agg_buffer> alpha_dst_out;
typedef AggCompOpAdapter<comp_dst_atop, agg_buffer> alpha_dst_atop;
typedef AggCompOpAdapter<comp_xor, agg_buffer> alpha_xor;
typedef AggCompOpAdapter<comp_clear, agg_buffer> alpha_clear;
typedef AggCompOpAdapter<comp_difference, agg_buffer> alpha_difference;
typedef AggCompOpAdapter<comp_lighten, agg_buffer> alpha_lighten;
typedef AggCompOpAdapter<comp_darken, agg_buffer> alpha_darken;
enum base_scale_e
{
base_shift = color_type::base_shift,
@ -146,6 +177,17 @@ class PixelFormat {
blend_solid_span fBlendSolidVSpan;
blend_color_span fBlendColorHSpan;
blend_color_span fBlendColorVSpan;
template<typename T>
void SetAggCompOpAdapter()
{
fBlendPixel = T::blend_pixel;
fBlendHLine = T::blend_hline;
fBlendSolidHSpanSubpix = T::blend_solid_hspan_subpix;
fBlendSolidHSpan = T::blend_solid_hspan;
fBlendSolidVSpan = T::blend_solid_vspan;
fBlendColorHSpan = T::blend_color_hspan;
}
};
// inlined functions

View File

@ -5,6 +5,14 @@
#include <stdio.h>
#include <string.h>
//#define DUMP_BLENDING_RESULTS
#ifdef DUMP_BLENDING_RESULTS
#include <BitmapStream.h>
#include <File.h>
#include <TranslatorRoster.h>
#include <String.h>
#endif
uint32 kBitmapBits[] = {
0x00777477, 0x00777477, 0x00777477, 0x00777477, 0x00777477, 0x00777477,
0x00777477, 0x00777477, 0x00777477, 0x00777477, 0x00777477, 0x00777477,
@ -188,6 +196,8 @@ virtual void Draw(BRect updateRect);
private:
BBitmap * fBitmap;
BBitmap * fTriangleLeft;
BBitmap * fTriangleRight;
};
@ -212,7 +222,7 @@ private:
DrawingModeApp::DrawingModeApp()
: BApplication("application/x.vnd-Haiku.DrawingModeTest")
{
fWindow = new DrawingModeWindow(BRect(200, 200, 380, 600));
fWindow = new DrawingModeWindow(BRect(200, 200, 760, 800));
fWindow->Show();
}
@ -234,12 +244,34 @@ DrawingModeView::DrawingModeView(BRect frame)
{
fBitmap = new BBitmap(BRect(0, 0, 31, 31), B_RGB32);
memcpy(fBitmap->Bits(), kBitmapBits, fBitmap->BitsLength());
uint32 triangleLeftBits[32 * 32] = { 0 };
uint32 triangleRightBits[32 * 32] = { 0 };
for(int y = 0; y < 32; ++y) {
for(int x = 0; x < 32; ++x) {
if(x < 32 - y) {
triangleLeftBits[y * 32 + x] = 0xffff0000;
}
if(x >= y) {
triangleRightBits[y * 32 + x] = 0xff0000ff;
}
}
}
fTriangleLeft = new BBitmap(BRect(0, 0, 31, 31), B_RGBA32);
memcpy(fTriangleLeft->Bits(), triangleLeftBits,
fTriangleLeft->BitsLength());
fTriangleRight = new BBitmap(BRect(0, 0, 31, 31), B_RGBA32);
memcpy(fTriangleRight->Bits(), triangleRightBits,
fTriangleRight->BitsLength());
}
DrawingModeView::~DrawingModeView()
{
delete fBitmap;
delete fTriangleLeft;
delete fTriangleRight;
}
@ -256,21 +288,45 @@ DrawingModeView::Draw(BRect updateRect)
BRect bitmapBounds = fBitmap->Bounds();
int32 imageHeight = bitmapBounds.IntegerHeight() + 10;
int32 imageWidth = bitmapBounds.IntegerWidth() + 10;
BRect triangleBounds = fTriangleLeft->Bounds();
int32 triangleHeight = triangleBounds.IntegerHeight() + 10;
int32 triangleWidth = triangleBounds.IntegerWidth() + 10;
#define MODE(m) { m, #m }
struct {
drawing_mode mode;
const char *name;
} drawingModes[] = {
{ B_OP_COPY, "B_OP_COPY" },
{ B_OP_OVER, "B_OP_OVER" },
{ B_OP_ERASE, "B_OP_ERASE" },
{ B_OP_INVERT, "B_OP_INVERT" },
{ B_OP_SELECT, "B_OP_SELECT" },
{ B_OP_ADD, "B_OP_ADD" },
{ B_OP_SUBTRACT, "B_OP_SUBTRACT" },
{ B_OP_BLEND, "B_OP_BLEND" },
{ B_OP_MIN, "B_OP_MIN" },
{ B_OP_MAX, "B_OP_MAX" }
MODE(B_OP_COPY),
MODE(B_OP_OVER),
MODE(B_OP_ERASE),
MODE(B_OP_INVERT),
MODE(B_OP_SELECT),
MODE(B_OP_ADD),
MODE(B_OP_SUBTRACT),
MODE(B_OP_BLEND),
MODE(B_OP_MIN),
MODE(B_OP_MAX)
};
struct {
alpha_function mode;
const char *name;
} blendingModes[] = {
MODE(B_ALPHA_COMPOSITE_SOURCE_OVER),
MODE(B_ALPHA_COMPOSITE_SOURCE_IN),
MODE(B_ALPHA_COMPOSITE_SOURCE_OUT),
MODE(B_ALPHA_COMPOSITE_SOURCE_ATOP),
MODE(B_ALPHA_COMPOSITE_DESTINATION_OVER),
MODE(B_ALPHA_COMPOSITE_DESTINATION_IN),
MODE(B_ALPHA_COMPOSITE_DESTINATION_OUT),
MODE(B_ALPHA_COMPOSITE_DESTINATION_ATOP),
MODE(B_ALPHA_COMPOSITE_XOR),
MODE(B_ALPHA_COMPOSITE_CLEAR),
MODE(B_ALPHA_COMPOSITE_DIFFERENCE),
MODE(B_ALPHA_COMPOSITE_LIGHTEN),
MODE(B_ALPHA_COMPOSITE_DARKEN)
};
int32 modeCount = sizeof(drawingModes) / sizeof(drawingModes[0]);
@ -312,6 +368,92 @@ DrawingModeView::Draw(BRect updateRect)
DrawString(drawingModes[i].name, BPoint(imageWidth * 2,
imageHeight * i + 20));
}
#ifdef DUMP_BLENDING_RESULTS
BTranslatorRoster* roster = BTranslatorRoster::Default();
if (roster == NULL)
abort();
translator_id* outId;
int32 outCount;
translation_format pngFormat;
roster->GetAllTranslators(&outId, &outCount);
for(int32 i = 0; i < outCount; ++i) {
const translation_format* formats;
int32 formatCount;
roster->GetOutputFormats(outId[i], &formats, &formatCount);
for(int32 j = 0; j < formatCount; ++j) {
if(strcmp(formats[j].MIME, "image/png") == 0) {
pngFormat = formats[j];
}
}
}
status_t r = B_OK;
{
BFile file("DESTINATION.png",
B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
BBitmapStream stream(fTriangleLeft);
r = roster->Translate(&stream, NULL, NULL, &file, pngFormat.type);
if(r != B_OK)
fprintf(stderr, "Failed to save PNG file for destination\n");
stream.DetachBitmap(&fTriangleLeft);
}
{
BFile file("SOURCE.png", B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
BBitmapStream stream(fTriangleRight);
r = roster->Translate(&stream, NULL, NULL, &file, pngFormat.type);
if(r != B_OK)
fprintf(stderr, "Failed to save PNG file for source\n");
stream.DetachBitmap(&fTriangleRight);
}
#endif
modeCount = sizeof(blendingModes) / sizeof(blendingModes[0]);
const int columnOffset = 180;
BView *blitter = new BView(BRect(0, 0, 31, 31),
"blitter", B_FOLLOW_ALL, B_WILL_DRAW);
BBitmap *resultBitmap = new BBitmap(BRect(0, 0, 31, 31),
B_RGBA32, true, false);
resultBitmap->AddChild(blitter);
for (int32 i = 0; i < modeCount; i++) {
resultBitmap->Lock();
blitter->SetDrawingMode(B_OP_COPY);
blitter->SetHighColor(0, 0, 0, 0);
blitter->FillRect(resultBitmap->Bounds());
blitter->DrawBitmap(fTriangleLeft, B_ORIGIN);
blitter->SetDrawingMode(B_OP_ALPHA);
blitter->SetBlendingMode(B_PIXEL_ALPHA, blendingModes[i].mode);
blitter->DrawBitmap(fTriangleRight, B_ORIGIN);
resultBitmap->Unlock();
#ifdef DUMP_BLENDING_RESULTS
BBitmapStream stream(resultBitmap);
BString fileName(blendingModes[i].name);
BFile file(fileName.Append(".png"),
B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
r = roster->Translate(&stream, NULL, NULL, &file, pngFormat.type);
if(r != B_OK) {
fprintf(stderr, "Failed to save PNG file for %s\n",
blendingModes[i].name);
}
stream.DetachBitmap(&resultBitmap);
#endif
SetDrawingMode(B_OP_ALPHA);
SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
DrawBitmap(resultBitmap, BPoint(columnOffset, triangleHeight * i));
SetDrawingMode(B_OP_OVER);
DrawString(blendingModes[i].name, BPoint(columnOffset + triangleWidth,
triangleHeight * i + 20));
}
resultBitmap->Lock();
resultBitmap->RemoveChild(blitter);
delete resultBitmap;
delete blitter;
}

View File

@ -7,5 +7,10 @@ UseHeaders [ FDirName os interface ] ;
Application DrawingModes :
DrawingModes.cpp
: [ TargetLibstdc++ ] be
: [ TargetLibstdc++ ] be translation
;
if ( $(TARGET_PLATFORM) = libbe_test ) {
HaikuInstall install-test-apps : $(HAIKU_APP_TEST_DIR) : DrawingModes
: tests!apps ;
}