* implemented a Translator for WonderBrush image files, these files contain
the layer bitmaps, all the Translater has to do is compose the layers, tested and works with all my WonderBrush images, hopefully contains no memory leaks... git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19211 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
55b40aa53a
commit
73a2ffba3b
@ -12,3 +12,4 @@ SubInclude HAIKU_TOP src add-ons translators rtf ;
|
||||
SubInclude HAIKU_TOP src add-ons translators sgi ;
|
||||
SubInclude HAIKU_TOP src add-ons translators stxt ;
|
||||
SubInclude HAIKU_TOP src add-ons translators tga ;
|
||||
SubInclude HAIKU_TOP src add-ons translators wonderbrush ;
|
||||
|
215
src/add-ons/translators/wonderbrush/Canvas.cpp
Normal file
215
src/add-ons/translators/wonderbrush/Canvas.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#include "Canvas.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Entry.h>
|
||||
#include <Message.h>
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
#include "Layer.h"
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// constructor
|
||||
Canvas::Canvas(BRect frame)
|
||||
: BList(10),
|
||||
fBounds(frame)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
Canvas::~Canvas()
|
||||
{
|
||||
MakeEmpty();
|
||||
}
|
||||
|
||||
// IsValid
|
||||
bool
|
||||
Canvas::IsValid() const
|
||||
{
|
||||
return fBounds.IsValid();
|
||||
}
|
||||
|
||||
// MakeEmpty
|
||||
void
|
||||
Canvas::MakeEmpty()
|
||||
{
|
||||
int32 count = CountLayers();
|
||||
for (int32 i = 0; i < count; i++)
|
||||
delete LayerAtFast(i);
|
||||
BList::MakeEmpty();
|
||||
}
|
||||
|
||||
// AddLayer
|
||||
bool
|
||||
Canvas::AddLayer(Layer* layer)
|
||||
{
|
||||
return AddLayer(layer, CountLayers());
|
||||
}
|
||||
|
||||
// AddLayer
|
||||
bool
|
||||
Canvas::AddLayer(Layer* layer, int32 index)
|
||||
{
|
||||
return layer && AddItem((void*)layer, index);
|
||||
}
|
||||
|
||||
// RemoveLayer
|
||||
Layer*
|
||||
Canvas::RemoveLayer(int32 index)
|
||||
{
|
||||
return (Layer*)RemoveItem(index);
|
||||
}
|
||||
|
||||
// RemoveLayer
|
||||
bool
|
||||
Canvas::RemoveLayer(Layer* layer)
|
||||
{
|
||||
return RemoveItem((void*)layer);
|
||||
}
|
||||
|
||||
// LayerAt
|
||||
Layer*
|
||||
Canvas::LayerAt(int32 index) const
|
||||
{
|
||||
return (Layer*)ItemAt(index);
|
||||
}
|
||||
|
||||
// LayerAtFast
|
||||
Layer*
|
||||
Canvas::LayerAtFast(int32 index) const
|
||||
{
|
||||
return (Layer*)ItemAtFast(index);
|
||||
}
|
||||
|
||||
// IndexOf
|
||||
int32
|
||||
Canvas::IndexOf(Layer* layer) const
|
||||
{
|
||||
return BList::IndexOf((void*)layer);
|
||||
}
|
||||
|
||||
// CountLayers
|
||||
int32
|
||||
Canvas::CountLayers() const
|
||||
{
|
||||
return CountItems();
|
||||
}
|
||||
|
||||
// HasLayer
|
||||
bool
|
||||
Canvas::HasLayer(Layer* layer) const
|
||||
{
|
||||
return HasItem((void*)layer);
|
||||
}
|
||||
|
||||
// SetBounds
|
||||
void
|
||||
Canvas::SetBounds(BRect bounds)
|
||||
{
|
||||
if (bounds.IsValid())
|
||||
fBounds = bounds;
|
||||
}
|
||||
|
||||
// Bounds
|
||||
BRect
|
||||
Canvas::Bounds() const
|
||||
{
|
||||
return fBounds;
|
||||
}
|
||||
|
||||
// Compose
|
||||
void
|
||||
Canvas::Compose(BBitmap* into, BRect area) const
|
||||
{
|
||||
if (into && into->IsValid()
|
||||
&& area.IsValid() && area.Intersects(into->Bounds())) {
|
||||
area = area & into->Bounds();
|
||||
int32 count = CountLayers();
|
||||
for (int32 i = count - 1; Layer* layer = LayerAt(i); i--) {
|
||||
layer->Compose(into, area);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bitmap
|
||||
BBitmap*
|
||||
Canvas::Bitmap() const
|
||||
{
|
||||
BBitmap* bitmap = new BBitmap(fBounds, 0, B_RGBA32);
|
||||
if (!bitmap->IsValid()) {
|
||||
delete bitmap;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// this bitmap is uninitialized, clear to black/fully transparent
|
||||
memset(bitmap->Bits(), 0, bitmap->BitsLength());
|
||||
Compose(bitmap, fBounds);
|
||||
// remove image data where alpha = 0 to improve compression later on
|
||||
uint8* bits = (uint8*)bitmap->Bits();
|
||||
uint32 bpr = bitmap->BytesPerRow();
|
||||
uint32 width = bitmap->Bounds().IntegerWidth() + 1;
|
||||
uint32 height = bitmap->Bounds().IntegerHeight() + 1;
|
||||
while (height > 0) {
|
||||
uint8* bitsHandle = bits;
|
||||
for (uint32 x = 0; x < width; x++) {
|
||||
if (!bitsHandle[3]) {
|
||||
bitsHandle[0] = 0;
|
||||
bitsHandle[1] = 0;
|
||||
bitsHandle[2] = 0;
|
||||
}
|
||||
bitsHandle += 4;
|
||||
}
|
||||
bits += bpr;
|
||||
height--;
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const char* LAYER_KEY = "layer";
|
||||
static const char* BOUNDS_KEY = "bounds";
|
||||
|
||||
// Unarchive
|
||||
status_t
|
||||
Canvas::Unarchive(const BMessage* archive)
|
||||
{
|
||||
if (!archive)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// restore bounds
|
||||
BRect bounds;
|
||||
if (archive->FindRect(BOUNDS_KEY, &bounds) < B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
fBounds = bounds;
|
||||
// restore each layer
|
||||
BMessage layerMessage;
|
||||
for (int32 i = 0;
|
||||
archive->FindMessage(LAYER_KEY, i, &layerMessage) == B_OK;
|
||||
i++) {
|
||||
|
||||
Layer* layer = new (nothrow) Layer();
|
||||
if (!layer || layer->Unarchive(&layerMessage) < B_OK
|
||||
|| !AddLayer(layer)) {
|
||||
delete layer;
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
58
src/add-ons/translators/wonderbrush/Canvas.h
Normal file
58
src/add-ons/translators/wonderbrush/Canvas.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef CANVAS_H
|
||||
#define CANVAS_H
|
||||
|
||||
#include <List.h>
|
||||
#include <Rect.h>
|
||||
#include <String.h>
|
||||
|
||||
struct entry_ref;
|
||||
|
||||
class BBitmap;
|
||||
class BMessage;
|
||||
class Layer;
|
||||
|
||||
class Canvas : private BList {
|
||||
public:
|
||||
Canvas(BRect frame);
|
||||
~Canvas();
|
||||
|
||||
bool IsValid() const;
|
||||
void MakeEmpty();
|
||||
|
||||
// list functionality
|
||||
bool AddLayer(Layer* layer);
|
||||
bool AddLayer(Layer* layer, int32 index);
|
||||
|
||||
Layer* RemoveLayer(int32 index);
|
||||
bool RemoveLayer(Layer* layer);
|
||||
|
||||
Layer* LayerAt(int32 index) const;
|
||||
Layer* LayerAtFast(int32 index) const;
|
||||
int32 IndexOf(Layer* layer) const;
|
||||
int32 CountLayers() const;
|
||||
bool HasLayer(Layer* layer) const;
|
||||
|
||||
void SetBounds(BRect bounds);
|
||||
BRect Bounds() const;
|
||||
|
||||
// composes layers on top of passed bitmap
|
||||
void Compose(BBitmap* into, BRect area) const;
|
||||
// returns entire composition in new bitmap
|
||||
BBitmap* Bitmap() const;
|
||||
|
||||
// loading
|
||||
status_t Unarchive(const BMessage* archive);
|
||||
|
||||
private:
|
||||
BRect fBounds;
|
||||
};
|
||||
|
||||
#endif // CANVAS_H
|
38
src/add-ons/translators/wonderbrush/Jamfile
Normal file
38
src/add-ons/translators/wonderbrush/Jamfile
Normal file
@ -0,0 +1,38 @@
|
||||
SubDir HAIKU_TOP src add-ons translators wonderbrush ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
# Include BaseTranslator code from shared directory
|
||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons translators shared ] ;
|
||||
|
||||
# Include support sub folder
|
||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons translators wonderbrush support ] ;
|
||||
|
||||
UseLibraryHeaders zlib ;
|
||||
|
||||
Translator WonderBrushTranslator :
|
||||
# shared classes
|
||||
BaseTranslator.cpp
|
||||
TranslatorSettings.cpp
|
||||
TranslatorWindow.cpp
|
||||
|
||||
# WonderBrushTranslator classes
|
||||
Canvas.cpp
|
||||
Layer.cpp
|
||||
WonderBrushImage.cpp
|
||||
WonderBrushMain.cpp
|
||||
WonderBrushTranslator.cpp
|
||||
WonderBrushView.cpp
|
||||
|
||||
# support
|
||||
bitmap_compression.cpp
|
||||
blending.cpp
|
||||
lab_convert.cpp
|
||||
|
||||
: be translation z
|
||||
;
|
||||
|
||||
Package haiku-translationkit-cvs :
|
||||
WonderBrushTranslator :
|
||||
boot home config add-ons Translators ;
|
||||
|
386
src/add-ons/translators/wonderbrush/Layer.cpp
Normal file
386
src/add-ons/translators/wonderbrush/Layer.cpp
Normal file
@ -0,0 +1,386 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#include "Layer.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Message.h>
|
||||
|
||||
#include "bitmap_compression.h"
|
||||
#include "blending.h"
|
||||
#include "lab_convert.h"
|
||||
#include "support.h"
|
||||
|
||||
// constructor
|
||||
Layer::Layer()
|
||||
: fBitmap(NULL),
|
||||
fBounds(0.0, 0.0, -1.0, -1.0),
|
||||
fAlpha(1.0),
|
||||
fMode(MODE_NORMAL),
|
||||
fFlags(0)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
Layer::~Layer()
|
||||
{
|
||||
delete fBitmap;
|
||||
}
|
||||
|
||||
// Compose
|
||||
status_t
|
||||
Layer::Compose(const BBitmap* into, BRect area)
|
||||
{
|
||||
if (!fBitmap || !fBitmap->IsValid()
|
||||
|| (fBitmap->ColorSpace() != B_RGBA32 && fBitmap->ColorSpace() != B_RGB32))
|
||||
return B_NO_INIT;
|
||||
|
||||
status_t status = B_BAD_VALUE;
|
||||
if (!into || !area.IsValid() || (status = into->InitCheck()) < B_OK)
|
||||
return status;
|
||||
|
||||
// make sure we don't access memory outside of our bitmap
|
||||
area = area & fBitmap->Bounds();
|
||||
|
||||
BRect r = ActiveBounds();
|
||||
if (!r.IsValid() || (fFlags & FLAG_INVISIBLE) || !r.Intersects(area))
|
||||
return B_OK;
|
||||
|
||||
r = r & area;
|
||||
int32 left, top, right, bottom;
|
||||
rect_to_int(r, left, top, right, bottom);
|
||||
|
||||
uint8* src = (uint8*)fBitmap->Bits();
|
||||
uint8* dst = (uint8*)into->Bits();
|
||||
uint32 bpr = into->BytesPerRow();
|
||||
src += 4 * left + bpr * top;
|
||||
dst += 4 * left + bpr * top;
|
||||
uint8 alphaOverride = (uint8)(fAlpha * 255);
|
||||
|
||||
switch (fMode) {
|
||||
|
||||
case MODE_SOFT_LIGHT:
|
||||
for (; top <= bottom; top++) {
|
||||
uint8* srcHandle = src;
|
||||
uint8* dstHandle = dst;
|
||||
for (int32 x = left; x <= right; x++) {
|
||||
if (srcHandle[3] > 0) {
|
||||
uint8 c1 = dstHandle[0] * srcHandle[0] >> 8;
|
||||
c1 = c1 + dstHandle[0] * (255 - ((255 - dstHandle[0]) * (255 - srcHandle[0]) >> 8) - c1) >> 8;
|
||||
c1 = (c1 * dstHandle[3] + srcHandle[0] * (255 - dstHandle[3])) >> 8;
|
||||
|
||||
uint8 c2 = dstHandle[1] * srcHandle[1] >> 8;
|
||||
c2 = c2 + dstHandle[1] * (255 - ((255 - dstHandle[1]) * (255 - srcHandle[1]) >> 8) - c2) >> 8;
|
||||
c2 = (c2 * dstHandle[3] + srcHandle[1] * (255 - dstHandle[3])) >> 8;
|
||||
|
||||
uint8 c3 = dstHandle[2] * srcHandle[2] >> 8;
|
||||
c3 = c3 + dstHandle[2] * (255 - ((255 - dstHandle[2]) * (255 - srcHandle[2]) >> 8) - c3) >> 8;
|
||||
c3 = (c3 * dstHandle[3] + srcHandle[2] * (255 - dstHandle[3])) >> 8;
|
||||
|
||||
blend_colors(dstHandle, (srcHandle[3] * alphaOverride) >> 8,
|
||||
c1, c2, c3);
|
||||
}
|
||||
srcHandle += 4;
|
||||
dstHandle += 4;
|
||||
}
|
||||
src += bpr;
|
||||
dst += bpr;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_LIGHTEN:
|
||||
for (; top <= bottom; top++) {
|
||||
uint8* srcHandle = src;
|
||||
uint8* dstHandle = dst;
|
||||
for (int32 x = left; x <= right; x++) {
|
||||
if (srcHandle[3] > 0) {
|
||||
// compose
|
||||
uint8 c1 = (max_c(srcHandle[0], dstHandle[0]) * dstHandle[3]
|
||||
+ srcHandle[0] * (255 - dstHandle[3])) / 255;
|
||||
uint8 c2 = (max_c(srcHandle[1], dstHandle[1]) * dstHandle[3]
|
||||
+ srcHandle[1] * (255 - dstHandle[3])) / 255;
|
||||
uint8 c3 = (max_c(srcHandle[2], dstHandle[2]) * dstHandle[3]
|
||||
+ srcHandle[2] * (255 - dstHandle[3])) / 255;
|
||||
blend_colors(dstHandle, (srcHandle[3] * alphaOverride) / 255,
|
||||
c1, c2, c3);
|
||||
}
|
||||
srcHandle += 4;
|
||||
dstHandle += 4;
|
||||
}
|
||||
src += bpr;
|
||||
dst += bpr;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_DARKEN:
|
||||
for (; top <= bottom; top++) {
|
||||
uint8* srcHandle = src;
|
||||
uint8* dstHandle = dst;
|
||||
for (int32 x = left; x <= right; x++) {
|
||||
if (srcHandle[3] > 0) {
|
||||
// compose
|
||||
uint8 c1 = (min_c(srcHandle[0], dstHandle[0]) * dstHandle[3]
|
||||
+ srcHandle[0] * (255 - dstHandle[3])) / 255;
|
||||
uint8 c2 = (min_c(srcHandle[1], dstHandle[1]) * dstHandle[3]
|
||||
+ srcHandle[1] * (255 - dstHandle[3])) / 255;
|
||||
uint8 c3 = (min_c(srcHandle[2], dstHandle[2]) * dstHandle[3]
|
||||
+ srcHandle[2] * (255 - dstHandle[3])) / 255;
|
||||
blend_colors(dstHandle, (srcHandle[3] * alphaOverride) / 255,
|
||||
c1, c2, c3);
|
||||
}
|
||||
srcHandle += 4;
|
||||
dstHandle += 4;
|
||||
}
|
||||
src += bpr;
|
||||
dst += bpr;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_REPLACE_RED:
|
||||
for (; top <= bottom; top++) {
|
||||
uint8* srcHandle = src;
|
||||
uint8* dstHandle = dst;
|
||||
for (int32 x = left; x <= right; x++) {
|
||||
if (srcHandle[3] > 0) {
|
||||
// compose
|
||||
uint32 alpha = srcHandle[3] * alphaOverride;
|
||||
dstHandle[2] = (srcHandle[2] * alpha
|
||||
+ dstHandle[2] * (65025 - alpha)) / 65025;
|
||||
}
|
||||
srcHandle += 4;
|
||||
dstHandle += 4;
|
||||
}
|
||||
src += bpr;
|
||||
dst += bpr;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_REPLACE_GREEN:
|
||||
for (; top <= bottom; top++) {
|
||||
uint8* srcHandle = src;
|
||||
uint8* dstHandle = dst;
|
||||
for (int32 x = left; x <= right; x++) {
|
||||
if (srcHandle[3] > 0) {
|
||||
// compose
|
||||
uint32 alpha = srcHandle[3] * alphaOverride;
|
||||
dstHandle[1] = (srcHandle[1] * alpha
|
||||
+ dstHandle[1] * (65025 - alpha)) / 65025;
|
||||
}
|
||||
srcHandle += 4;
|
||||
dstHandle += 4;
|
||||
}
|
||||
src += bpr;
|
||||
dst += bpr;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_REPLACE_BLUE:
|
||||
for (; top <= bottom; top++) {
|
||||
uint8* srcHandle = src;
|
||||
uint8* dstHandle = dst;
|
||||
for (int32 x = left; x <= right; x++) {
|
||||
if (srcHandle[3] > 0) {
|
||||
// compose
|
||||
uint32 alpha = srcHandle[3] * alphaOverride;
|
||||
dstHandle[0] = (srcHandle[0] * alpha
|
||||
+ dstHandle[0] * (65025 - alpha)) / 65025;
|
||||
}
|
||||
srcHandle += 4;
|
||||
dstHandle += 4;
|
||||
}
|
||||
src += bpr;
|
||||
dst += bpr;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_MULTIPLY_INVERSE_ALPHA:
|
||||
for (; top <= bottom; top++) {
|
||||
uint8* srcHandle = src;
|
||||
uint8* dstHandle = dst;
|
||||
for (int32 x = left; x <= right; x++) {
|
||||
// compose
|
||||
uint8 temp = min_c(dstHandle[3], 255 - srcHandle[3]);
|
||||
dstHandle[3] = (dstHandle[3] * (255 - alphaOverride) + temp * alphaOverride) / 255;
|
||||
srcHandle += 4;
|
||||
dstHandle += 4;
|
||||
}
|
||||
src += bpr;
|
||||
dst += bpr;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_MULTIPLY_ALPHA:
|
||||
for (; top <= bottom; top++) {
|
||||
uint8* srcHandle = src;
|
||||
uint8* dstHandle = dst;
|
||||
for (int32 x = left; x <= right; x++) {
|
||||
// compose
|
||||
uint8 temp = min_c(dstHandle[3], srcHandle[3]);
|
||||
dstHandle[3] = (dstHandle[3] * (255 - alphaOverride) + temp * alphaOverride) / 255;
|
||||
srcHandle += 4;
|
||||
dstHandle += 4;
|
||||
}
|
||||
src += bpr;
|
||||
dst += bpr;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_LUMINANCE:
|
||||
for (; top <= bottom; top++) {
|
||||
uint8* srcHandle = src;
|
||||
uint8* dstHandle = dst;
|
||||
for (int32 x = left; x <= right; x++) {
|
||||
if (srcHandle[3] > 0) {
|
||||
// compose
|
||||
uint8 r = dstHandle[2];
|
||||
uint8 g = dstHandle[1];
|
||||
uint8 b = dstHandle[0];
|
||||
uint8 alpha = dstHandle[3];
|
||||
replace_luminance(r, g, b, srcHandle[2], srcHandle[1], srcHandle[0]);
|
||||
blend_colors(dstHandle, (srcHandle[3] * alphaOverride) / 255,
|
||||
b, g, r);
|
||||
dstHandle[3] = alpha;
|
||||
}
|
||||
srcHandle += 4;
|
||||
dstHandle += 4;
|
||||
}
|
||||
src += bpr;
|
||||
dst += bpr;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_INVERSE_MULTIPLY:
|
||||
for (; top <= bottom; top++) {
|
||||
uint8* srcHandle = src;
|
||||
uint8* dstHandle = dst;
|
||||
for (int32 x = left; x <= right; x++) {
|
||||
if (srcHandle[3] > 0) {
|
||||
// compose
|
||||
uint8 c1 = 255 - ((((255 - srcHandle[0]) * (255 - dstHandle[0])) / 255) * dstHandle[3]
|
||||
+ (255 - srcHandle[0]) * (255 - dstHandle[3])) / 255;
|
||||
uint8 c2 = 255 - ((((255 - srcHandle[1]) * (255 - dstHandle[1])) / 255) * dstHandle[3]
|
||||
+ (255 - srcHandle[1]) * (255 - dstHandle[3])) / 255;
|
||||
uint8 c3 = 255 - ((((255 - srcHandle[2]) * (255 - dstHandle[2])) / 255) * dstHandle[3]
|
||||
+ (255 - srcHandle[2]) * (255 - dstHandle[3])) / 255;
|
||||
blend_colors(dstHandle, (srcHandle[3] * alphaOverride) / 255,
|
||||
c1, c2, c3);
|
||||
}
|
||||
srcHandle += 4;
|
||||
dstHandle += 4;
|
||||
}
|
||||
src += bpr;
|
||||
dst += bpr;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_MULTIPLY:
|
||||
for (; top <= bottom; top++) {
|
||||
uint8* srcHandle = src;
|
||||
uint8* dstHandle = dst;
|
||||
for (int32 x = left; x <= right; x++) {
|
||||
if (srcHandle[3] > 0) {
|
||||
// compose
|
||||
uint8 c1 = (((srcHandle[0] * dstHandle[0]) / 255) * dstHandle[3]
|
||||
+ srcHandle[0] * (255 - dstHandle[3])) / 255;
|
||||
uint8 c2 = (((srcHandle[1] * dstHandle[1]) / 255) * dstHandle[3]
|
||||
+ srcHandle[1] * (255 - dstHandle[3])) / 255;
|
||||
uint8 c3 = (((srcHandle[2] * dstHandle[2]) / 255) * dstHandle[3]
|
||||
+ srcHandle[2] * (255 - dstHandle[3])) / 255;
|
||||
blend_colors(dstHandle, (srcHandle[3] * alphaOverride) / 255,
|
||||
c1, c2, c3);
|
||||
}
|
||||
srcHandle += 4;
|
||||
dstHandle += 4;
|
||||
}
|
||||
src += bpr;
|
||||
dst += bpr;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_NORMAL:
|
||||
default:
|
||||
if (alphaOverride == 255) {
|
||||
// use an optimized version that composes the bitmaps directly
|
||||
for (; top <= bottom; top++) {
|
||||
uint8* srcHandle = src;
|
||||
uint8* dstHandle = dst;
|
||||
for (int32 x = left; x <= right; x++) {
|
||||
blend_colors(dstHandle, srcHandle);
|
||||
srcHandle += 4;
|
||||
dstHandle += 4;
|
||||
}
|
||||
src += bpr;
|
||||
dst += bpr;
|
||||
}
|
||||
} else {
|
||||
for (; top <= bottom; top++) {
|
||||
uint8* srcHandle = src;
|
||||
uint8* dstHandle = dst;
|
||||
for (int32 x = left; x <= right; x++) {
|
||||
blend_colors(dstHandle, srcHandle, alphaOverride);
|
||||
srcHandle += 4;
|
||||
dstHandle += 4;
|
||||
}
|
||||
src += bpr;
|
||||
dst += bpr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Unarchive
|
||||
status_t
|
||||
Layer::Unarchive(const BMessage* archive)
|
||||
{
|
||||
if (!archive)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// restore attributes
|
||||
float alpha;
|
||||
if (archive->FindFloat("alpha", &alpha) == B_OK) {
|
||||
constrain(alpha, 0.0, 1.0);
|
||||
fAlpha = alpha;
|
||||
} else
|
||||
fAlpha = 1.0;
|
||||
if (archive->FindInt32("mode", (int32*)&fMode) < B_OK)
|
||||
fMode = MODE_NORMAL;
|
||||
if (archive->FindInt32("flags", (int32*)&fFlags) < B_OK)
|
||||
fFlags = 0;
|
||||
|
||||
// delete current contents
|
||||
delete fBitmap;
|
||||
fBitmap = NULL;
|
||||
|
||||
status_t status = extract_bitmap(&fBitmap, archive, "current bitmap");
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
// "bounds" is where the layer actually has content
|
||||
BRect bounds;
|
||||
if (archive->FindRect("bounds", &bounds) == B_OK)
|
||||
fBounds = bounds;
|
||||
else
|
||||
fBounds.Set(0.0, 0.0, -1.0, -1.0);
|
||||
|
||||
// validate status of fBitmap
|
||||
if (!fBitmap)
|
||||
return B_ERROR;
|
||||
|
||||
status = fBitmap->InitCheck();
|
||||
if (status < B_OK) {
|
||||
delete fBitmap;
|
||||
fBitmap = NULL;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
68
src/add-ons/translators/wonderbrush/Layer.h
Normal file
68
src/add-ons/translators/wonderbrush/Layer.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef LAYER_H
|
||||
#define LAYER_H
|
||||
|
||||
#include <Rect.h>
|
||||
#include <String.h>
|
||||
|
||||
// property flags
|
||||
enum {
|
||||
FLAG_INVISIBLE = 0x01,
|
||||
};
|
||||
|
||||
// blending modes (as of WonderBrush 2.0)
|
||||
enum {
|
||||
MODE_NORMAL = 0,
|
||||
MODE_MULTIPLY = 1,
|
||||
MODE_INVERSE_MULTIPLY = 2,
|
||||
MODE_LUMINANCE = 3,
|
||||
MODE_MULTIPLY_ALPHA = 4,
|
||||
MODE_MULTIPLY_INVERSE_ALPHA = 5,
|
||||
|
||||
MODE_REPLACE_RED = 6,
|
||||
MODE_REPLACE_GREEN = 7,
|
||||
MODE_REPLACE_BLUE = 8,
|
||||
|
||||
MODE_DARKEN = 9,
|
||||
MODE_LIGHTEN = 10,
|
||||
|
||||
MODE_HARD_LIGHT = 11,
|
||||
MODE_SOFT_LIGHT = 12,
|
||||
};
|
||||
|
||||
class BBitmap;
|
||||
class BMessage;
|
||||
|
||||
class Layer {
|
||||
public:
|
||||
Layer();
|
||||
~Layer();
|
||||
|
||||
// active area of layer
|
||||
inline BRect ActiveBounds() const
|
||||
{ return fBounds; }
|
||||
|
||||
// composing
|
||||
status_t Compose(const BBitmap* into,
|
||||
BRect area);
|
||||
|
||||
// loading
|
||||
status_t Unarchive(const BMessage* archive);
|
||||
|
||||
protected:
|
||||
BBitmap* fBitmap;
|
||||
BRect fBounds;
|
||||
|
||||
float fAlpha;
|
||||
uint32 fMode;
|
||||
uint32 fFlags;
|
||||
};
|
||||
|
||||
#endif // LAYER_H
|
55
src/add-ons/translators/wonderbrush/WonderBrushImage.cpp
Normal file
55
src/add-ons/translators/wonderbrush/WonderBrushImage.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#include "WonderBrushImage.h"
|
||||
|
||||
#include "Canvas.h"
|
||||
|
||||
WonderBrushImage::WonderBrushImage()
|
||||
: fArchive(0UL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
WonderBrushImage::~WonderBrushImage()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WonderBrushImage::SetTo(BPositionIO* stream)
|
||||
{
|
||||
if (!stream)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// try to load the stream as a BMessage and probe it
|
||||
// to see wether it might be a WonderBrush image
|
||||
fArchive.MakeEmpty();
|
||||
status_t status = fArchive.Unflatten(stream);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
if (fArchive.HasMessage("layer") && fArchive.HasRect("bounds"))
|
||||
return B_OK;
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
BBitmap*
|
||||
WonderBrushImage::Bitmap() const
|
||||
{
|
||||
Canvas canvas(BRect(0.0, 0.0, -1.0, -1.0));
|
||||
|
||||
if (canvas.Unarchive(&fArchive) < B_OK)
|
||||
return NULL;
|
||||
|
||||
return canvas.Bitmap();
|
||||
}
|
||||
|
||||
|
31
src/add-ons/translators/wonderbrush/WonderBrushImage.h
Normal file
31
src/add-ons/translators/wonderbrush/WonderBrushImage.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef WONDERBRUSH_IMAGE_H
|
||||
#define WONDERBRUSH_IMAGE_H
|
||||
|
||||
#include <Message.h>
|
||||
|
||||
class BBitmap;
|
||||
class BPositionIO;
|
||||
class Canvas;
|
||||
|
||||
class WonderBrushImage {
|
||||
public:
|
||||
WonderBrushImage();
|
||||
virtual ~WonderBrushImage();
|
||||
|
||||
status_t SetTo(BPositionIO* stream);
|
||||
BBitmap* Bitmap() const;
|
||||
|
||||
private:
|
||||
BMessage fArchive;
|
||||
};
|
||||
|
||||
#endif // WONDERBRUSH_IMAGE_H
|
||||
|
26
src/add-ons/translators/wonderbrush/WonderBrushMain.cpp
Normal file
26
src/add-ons/translators/wonderbrush/WonderBrushMain.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
#include "WonderBrushTranslator.h"
|
||||
#include "TranslatorWindow.h"
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
BApplication app("application/x-vnd.haiku-wbi-translator");
|
||||
status_t result;
|
||||
result = LaunchTranslatorWindow(new WonderBrushTranslator,
|
||||
"WBI Settings", BRect(0, 0, 225, 175));
|
||||
if (result == B_OK) {
|
||||
app.Run();
|
||||
return 0;
|
||||
} else
|
||||
return 1;
|
||||
}
|
241
src/add-ons/translators/wonderbrush/WonderBrushTranslator.cpp
Normal file
241
src/add-ons/translators/wonderbrush/WonderBrushTranslator.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#include "WonderBrushTranslator.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <OS.h>
|
||||
|
||||
#include "blending.h"
|
||||
|
||||
#include "WonderBrushImage.h"
|
||||
#include "WonderBrushView.h"
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// The input formats that this translator supports.
|
||||
translation_format gInputFormats[] = {
|
||||
/*{
|
||||
B_TRANSLATOR_BITMAP,
|
||||
B_TRANSLATOR_BITMAP,
|
||||
BBT_IN_QUALITY,
|
||||
BBT_IN_CAPABILITY,
|
||||
"image/x-be-bitmap",
|
||||
"Be Bitmap Format (WonderBrushTranslator)"
|
||||
},*/
|
||||
{
|
||||
WBI_FORMAT,
|
||||
B_TRANSLATOR_BITMAP,
|
||||
WBI_IN_QUALITY,
|
||||
WBI_IN_CAPABILITY,
|
||||
"image/x-wonderbrush",
|
||||
"WonderBrush image"
|
||||
}
|
||||
};
|
||||
|
||||
// The output formats that this translator supports.
|
||||
translation_format gOutputFormats[] = {
|
||||
{
|
||||
B_TRANSLATOR_BITMAP,
|
||||
B_TRANSLATOR_BITMAP,
|
||||
BBT_OUT_QUALITY,
|
||||
BBT_OUT_CAPABILITY,
|
||||
"image/x-be-bitmap",
|
||||
"Be Bitmap Format (WonderBrushTranslator)"
|
||||
}/*,
|
||||
{
|
||||
WBI_FORMAT,
|
||||
B_TRANSLATOR_BITMAP,
|
||||
WBI_OUT_QUALITY,
|
||||
WBI_OUT_CAPABILITY,
|
||||
"image/x-wonderbrush",
|
||||
"WonderBrush image"
|
||||
}*/
|
||||
};
|
||||
|
||||
|
||||
// Default settings for the Translator
|
||||
TranSetting gDefaultSettings[] = {
|
||||
{ B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false },
|
||||
{ B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false }
|
||||
};
|
||||
|
||||
|
||||
BTranslator*
|
||||
make_nth_translator(int32 n, image_id you, uint32 flags, ...)
|
||||
{
|
||||
if (!n)
|
||||
return new WonderBrushTranslator();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
WonderBrushTranslator::WonderBrushTranslator()
|
||||
: BaseTranslator("WonderBrush Images", "WonderBrush image translator",
|
||||
WBI_TRANSLATOR_VERSION,
|
||||
gInputFormats, sizeof(gInputFormats) / sizeof(translation_format),
|
||||
gOutputFormats, sizeof(gOutputFormats) / sizeof(translation_format),
|
||||
"WBITranslator_Settings",
|
||||
gDefaultSettings, sizeof(gDefaultSettings) / sizeof(TranSetting),
|
||||
B_TRANSLATOR_BITMAP, WBI_FORMAT)
|
||||
{
|
||||
#if GAMMA_BLEND
|
||||
init_gamma_blending();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
WonderBrushTranslator::~WonderBrushTranslator()
|
||||
{
|
||||
#if GAMMA_BLEND
|
||||
uninit_gamma_blending();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
identify_wbi_header(BPositionIO* inSource, translator_info* outInfo,
|
||||
uint32 outType, WonderBrushImage** _wbImage = NULL)
|
||||
{
|
||||
status_t status = B_NO_MEMORY;
|
||||
// construct new SGIImage object and set it to the provided BPositionIO
|
||||
WonderBrushImage* wbImage = new(nothrow) WonderBrushImage();
|
||||
if (wbImage)
|
||||
status = wbImage->SetTo(inSource);
|
||||
|
||||
if (status >= B_OK) {
|
||||
if (outInfo) {
|
||||
outInfo->type = WBI_FORMAT;
|
||||
outInfo->group = B_TRANSLATOR_BITMAP;
|
||||
outInfo->quality = WBI_IN_QUALITY;
|
||||
outInfo->capability = WBI_IN_CAPABILITY;
|
||||
strcpy(outInfo->MIME, "image/x-wonderbrush");
|
||||
strcpy(outInfo->name, "WonderBrush image");
|
||||
}
|
||||
} else {
|
||||
delete wbImage;
|
||||
wbImage = NULL;
|
||||
}
|
||||
if (!_wbImage) {
|
||||
// close WonderBrushImage if caller is not interested in handle
|
||||
delete wbImage;
|
||||
} else {
|
||||
// leave WonderBrushImage open (if it is) and return handle if
|
||||
// caller needs it
|
||||
*_wbImage = wbImage;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WonderBrushTranslator::DerivedIdentify(BPositionIO* inSource,
|
||||
const translation_format* inFormat, BMessage* ioExtension,
|
||||
translator_info* outInfo, uint32 outType)
|
||||
{
|
||||
return identify_wbi_header(inSource, outInfo, outType);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WonderBrushTranslator::DerivedTranslate(BPositionIO* inSource,
|
||||
const translator_info* inInfo, BMessage* ioExtension,
|
||||
uint32 outType, BPositionIO* outDestination, int32 baseType)
|
||||
{
|
||||
if (baseType == 0)
|
||||
// if inSource is NOT in bits format
|
||||
return _TranslateFromWBI(inSource, outType, outDestination);
|
||||
else
|
||||
// if BaseTranslator did not properly identify the data as
|
||||
// bits or not bits
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
|
||||
|
||||
BView*
|
||||
WonderBrushTranslator::NewConfigView(TranslatorSettings* settings)
|
||||
{
|
||||
return new WonderBrushView(BRect(0, 0, 225, 175), "WBI Settings",
|
||||
B_FOLLOW_ALL, B_WILL_DRAW, settings);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
WonderBrushTranslator::_TranslateFromWBI(BPositionIO* inSource, uint32 outType,
|
||||
BPositionIO* outDestination)
|
||||
{
|
||||
// if copying WBI_FORMAT to WBI_FORMAT
|
||||
if (outType == WBI_FORMAT) {
|
||||
translate_direct_copy(inSource, outDestination);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
WonderBrushImage* wbImage = NULL;
|
||||
ssize_t ret = identify_wbi_header(inSource, NULL, outType, &wbImage);
|
||||
if (ret < B_OK)
|
||||
return ret;
|
||||
|
||||
bool headerOnly = false;
|
||||
bool dataOnly = false;
|
||||
|
||||
BBitmap* bitmap = wbImage->Bitmap();
|
||||
if (!bitmap)
|
||||
return B_ERROR;
|
||||
|
||||
uint32 width = bitmap->Bounds().IntegerWidth() + 1;
|
||||
uint32 height = bitmap->Bounds().IntegerHeight() + 1;
|
||||
color_space format = bitmap->ColorSpace();
|
||||
uint32 bytesPerRow = bitmap->BytesPerRow();
|
||||
|
||||
if (!dataOnly) {
|
||||
// Construct and write Be bitmap header
|
||||
TranslatorBitmap bitsHeader;
|
||||
bitsHeader.magic = B_TRANSLATOR_BITMAP;
|
||||
bitsHeader.bounds.left = 0;
|
||||
bitsHeader.bounds.top = 0;
|
||||
bitsHeader.bounds.right = width - 1;
|
||||
bitsHeader.bounds.bottom = height - 1;
|
||||
bitsHeader.rowBytes = bytesPerRow;
|
||||
bitsHeader.colors = format;
|
||||
bitsHeader.dataSize = bitsHeader.rowBytes * height;
|
||||
if ((ret = swap_data(B_UINT32_TYPE, &bitsHeader,
|
||||
sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN)) < B_OK) {
|
||||
return ret;
|
||||
} else
|
||||
ret = outDestination->Write(&bitsHeader, sizeof(TranslatorBitmap));
|
||||
}
|
||||
|
||||
if (ret >= B_OK && !headerOnly) {
|
||||
// read one row at a time and write out the results
|
||||
uint8* row = (uint8*)bitmap->Bits();
|
||||
for (uint32 y = 0; y < height && ret >= B_OK; y++) {
|
||||
ret = outDestination->Write(row, bytesPerRow);
|
||||
row += bytesPerRow;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delete bitmap;
|
||||
delete wbImage;
|
||||
|
||||
if (ret >= B_OK)
|
||||
ret = B_OK;
|
||||
|
||||
return (status_t)ret;
|
||||
}
|
||||
|
||||
|
68
src/add-ons/translators/wonderbrush/WonderBrushTranslator.h
Normal file
68
src/add-ons/translators/wonderbrush/WonderBrushTranslator.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef WONDERBRUSH_TRANSLATOR_H
|
||||
#define WONDERBRUSH_TRANSLATOR_H
|
||||
|
||||
#include <ByteOrder.h>
|
||||
#include <DataIO.h>
|
||||
#include <File.h>
|
||||
#include <fs_attr.h>
|
||||
#include <GraphicsDefs.h>
|
||||
#include <InterfaceDefs.h>
|
||||
#include <TranslationDefs.h>
|
||||
#include <Translator.h>
|
||||
#include <TranslatorFormats.h>
|
||||
|
||||
#include "BaseTranslator.h"
|
||||
|
||||
#define WBI_TRANSLATOR_VERSION B_TRANSLATION_MAKE_VERSION(1,0,0)
|
||||
|
||||
#define WBI_IN_QUALITY 1.0
|
||||
#define WBI_IN_CAPABILITY 1.0
|
||||
#define WBI_OUT_QUALITY 1.0
|
||||
#define WBI_OUT_CAPABILITY 1.0
|
||||
|
||||
#define BBT_IN_QUALITY 0.4
|
||||
#define BBT_IN_CAPABILITY 0.6
|
||||
#define BBT_OUT_QUALITY 0.4
|
||||
#define BBT_OUT_CAPABILITY 0.6
|
||||
|
||||
enum {
|
||||
WBI_FORMAT = 'WBI ',
|
||||
};
|
||||
|
||||
class WonderBrushTranslator : public BaseTranslator {
|
||||
public:
|
||||
WonderBrushTranslator();
|
||||
|
||||
virtual status_t DerivedIdentify(BPositionIO* inSource,
|
||||
const translation_format* inFormat,
|
||||
BMessage* ioExtension,
|
||||
translator_info* outInfo, uint32 outType);
|
||||
|
||||
virtual status_t DerivedTranslate(BPositionIO* inSource,
|
||||
const translator_info* inInfo,
|
||||
BMessage* ioExtension, uint32 outType,
|
||||
BPositionIO* outDestination,
|
||||
int32 baseType);
|
||||
|
||||
virtual BView* NewConfigView(TranslatorSettings* settings);
|
||||
|
||||
protected:
|
||||
virtual ~WonderBrushTranslator();
|
||||
// this is protected because the object is deleted by the
|
||||
// Release() function instead of being deleted directly by
|
||||
// the user
|
||||
|
||||
private:
|
||||
status_t _TranslateFromWBI(BPositionIO* inSource,
|
||||
uint32 outType, BPositionIO* outDestination);
|
||||
};
|
||||
|
||||
#endif // WONDERBRUSH_TRANSLATOR_H
|
182
src/add-ons/translators/wonderbrush/WonderBrushView.cpp
Normal file
182
src/add-ons/translators/wonderbrush/WonderBrushView.cpp
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#include "WonderBrushView.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <MenuBar.h>
|
||||
#include <MenuField.h>
|
||||
#include <MenuItem.h>
|
||||
#include <PopUpMenu.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include "WonderBrushImage.h"
|
||||
#include "WonderBrushTranslator.h"
|
||||
|
||||
const char* kAuthor = "Stephan Aßmus, <superstippi@gmx.de>";
|
||||
const char* kWBICopyright = "Copyright "B_UTF8_COPYRIGHT" 2006 Haiku Inc.";
|
||||
|
||||
|
||||
void
|
||||
add_menu_item(BMenu* menu,
|
||||
uint32 compression,
|
||||
const char* label,
|
||||
uint32 currentCompression)
|
||||
{
|
||||
BMessage* message = new BMessage(WonderBrushView::MSG_COMPRESSION_CHANGED);
|
||||
message->AddInt32("value", compression);
|
||||
BMenuItem* item = new BMenuItem(label, message);
|
||||
item->SetMarked(currentCompression == compression);
|
||||
menu->AddItem(item);
|
||||
}
|
||||
|
||||
|
||||
WonderBrushView::WonderBrushView(const BRect &frame, const char *name,
|
||||
uint32 resize, uint32 flags, TranslatorSettings *settings)
|
||||
: BView(frame, name, resize, flags),
|
||||
fSettings(settings)
|
||||
{
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
// figure out where the text ends
|
||||
font_height fh;
|
||||
be_bold_font->GetHeight(&fh);
|
||||
float xbold, ybold;
|
||||
xbold = fh.descent + 1;
|
||||
ybold = fh.ascent + fh.descent * 2 + fh.leading;
|
||||
|
||||
font_height plainh;
|
||||
be_plain_font->GetHeight(&plainh);
|
||||
float yplain;
|
||||
yplain = plainh.ascent + plainh.descent * 2 + plainh.leading;
|
||||
|
||||
ResizeToPreferred();
|
||||
}
|
||||
|
||||
|
||||
WonderBrushView::~WonderBrushView()
|
||||
{
|
||||
fSettings->Release();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WonderBrushView::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
default:
|
||||
BView::MessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WonderBrushView::AttachedToWindow()
|
||||
{
|
||||
// Hack for DataTranslations which doesn't resize visible area to requested by view
|
||||
// which makes some parts of bigger than usual translationviews out of visible area
|
||||
// so if it was loaded to DataTranslations resize window if needed
|
||||
BWindow *window = Window();
|
||||
if (!strcmp(window->Name(), "DataTranslations")) {
|
||||
BView *view = Parent();
|
||||
if (view) {
|
||||
BRect frame = view->Frame();
|
||||
float x, y;
|
||||
GetPreferredSize(&x, &y);
|
||||
if (frame.Width() < x || (frame.Height() - 48) < y) {
|
||||
x -= frame.Width();
|
||||
y -= frame.Height() - 48;
|
||||
if (x < 0) x = 0;
|
||||
if (y < 0) y = 0;
|
||||
|
||||
// DataTranslations has main view called "Background"
|
||||
// change it's resizing mode so it will always resize with window
|
||||
// also make sure view will be redrawed after resize
|
||||
view = window->FindView("Background");
|
||||
if (view) {
|
||||
view->SetResizingMode(B_FOLLOW_ALL);
|
||||
view->SetFlags(B_FULL_UPDATE_ON_RESIZE);
|
||||
}
|
||||
|
||||
// The same with "Info..." button, except redrawing, which isn't needed
|
||||
view = window->FindView("Info…");
|
||||
if (view)
|
||||
view->SetResizingMode(B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
|
||||
|
||||
window->ResizeBy( x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WonderBrushView::Draw(BRect area)
|
||||
{
|
||||
SetFont(be_bold_font);
|
||||
font_height fh;
|
||||
GetFontHeight(&fh);
|
||||
float xbold = fh.descent + 1;
|
||||
float ybold = fh.ascent + fh.descent * 2 + fh.leading;
|
||||
|
||||
BPoint offset(xbold, ybold);
|
||||
|
||||
const char* text = "WonderBrush Image Translator";
|
||||
DrawString(text, offset);
|
||||
|
||||
SetFont(be_plain_font);
|
||||
font_height plainh;
|
||||
GetFontHeight(&plainh);
|
||||
float yplain = plainh.ascent + plainh.descent * 2 + plainh.leading;
|
||||
|
||||
offset.y += yplain;
|
||||
|
||||
char detail[100];
|
||||
sprintf(detail, "Version %d.%d.%d %s",
|
||||
static_cast<int>(B_TRANSLATION_MAJOR_VERSION(WBI_TRANSLATOR_VERSION)),
|
||||
static_cast<int>(B_TRANSLATION_MINOR_VERSION(WBI_TRANSLATOR_VERSION)),
|
||||
static_cast<int>(B_TRANSLATION_REVISION_VERSION(WBI_TRANSLATOR_VERSION)),
|
||||
__DATE__);
|
||||
DrawString(detail, offset);
|
||||
|
||||
offset.y += 2 * ybold;
|
||||
|
||||
text = "written by:";
|
||||
DrawString(text, offset);
|
||||
offset.y += ybold;
|
||||
|
||||
DrawString(kAuthor, offset);
|
||||
offset.y += 2 * ybold;
|
||||
|
||||
DrawString(kWBICopyright, offset);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WonderBrushView::GetPreferredSize(float* width, float* height)
|
||||
{
|
||||
if (width) {
|
||||
// look at the two widest strings
|
||||
float width1 = StringWidth(kWBICopyright) + 15.0;
|
||||
float width2 = be_plain_font->StringWidth(kAuthor) + 15.0;
|
||||
|
||||
*width = max_c(width1, width2);
|
||||
}
|
||||
|
||||
if (height) {
|
||||
// take the height of the bold system font and
|
||||
// the number of lines of text we render
|
||||
font_height fh;
|
||||
be_bold_font->GetHeight(&fh);
|
||||
float ybold = fh.ascent + fh.descent * 2 + fh.leading;
|
||||
|
||||
*height = 7 * ybold;
|
||||
}
|
||||
}
|
43
src/add-ons/translators/wonderbrush/WonderBrushView.h
Normal file
43
src/add-ons/translators/wonderbrush/WonderBrushView.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef WONDERBRUSH_VIEW_H
|
||||
#define WONDERBRUSH_VIEW_H
|
||||
|
||||
#include <View.h>
|
||||
#include "TranslatorSettings.h"
|
||||
|
||||
class BMenuField;
|
||||
|
||||
class WonderBrushView : public BView {
|
||||
public:
|
||||
WonderBrushView(const BRect &frame, const char *name, uint32 resize,
|
||||
uint32 flags, TranslatorSettings *settings);
|
||||
// sets up the view
|
||||
|
||||
~WonderBrushView();
|
||||
// releases the SGITranslator settings
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
virtual void MessageReceived(BMessage *message);
|
||||
|
||||
virtual void Draw(BRect area);
|
||||
// draws information about the SGITranslator
|
||||
virtual void GetPreferredSize(float* width, float* height);
|
||||
|
||||
enum {
|
||||
MSG_COMPRESSION_CHANGED = 'cmch',
|
||||
};
|
||||
|
||||
private:
|
||||
TranslatorSettings *fSettings;
|
||||
// the actual settings for the translator,
|
||||
// shared with the translator
|
||||
};
|
||||
|
||||
#endif // WONDERBRUSH_VIEW_H
|
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Message.h>
|
||||
|
||||
enum {
|
||||
COMPRESSION_NONE = 0,
|
||||
COMPRESSION_ZLIB = 2,
|
||||
};
|
||||
|
||||
// compress_bitmap_zlib
|
||||
bool
|
||||
compress_bitmap_zlib(const BBitmap* bitmap, void** buffer, unsigned* size)
|
||||
{
|
||||
bool result = false;
|
||||
if (bitmap) {
|
||||
Bytef* src = (Bytef*)bitmap->Bits();
|
||||
uLong srcLength = bitmap->BitsLength();
|
||||
*size = (unsigned)ceilf(srcLength * 1.01) + 12;
|
||||
*buffer = malloc(*size);
|
||||
if (*buffer) {
|
||||
int ret = compress2((Bytef*)*buffer,
|
||||
(uLongf*)size,
|
||||
src,
|
||||
srcLength,
|
||||
3);
|
||||
if (ret == Z_OK) {
|
||||
//printf("zlib compressed %ld bytes bitmap into %d bytes (%f%%)\n", srcLength, *size, ((float)*size / (float)srcLength) * 100.0);
|
||||
if ((unsigned)ceilf(srcLength * 1.01) + 12 != *size)
|
||||
*buffer = realloc(*buffer, *size);
|
||||
result = true;
|
||||
} else {
|
||||
// error compressing
|
||||
free(*buffer);
|
||||
*buffer = NULL;
|
||||
*size = 0;
|
||||
fprintf(stderr, "zlib compression error: %d\n", ret);
|
||||
}
|
||||
} else
|
||||
*size = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// decompress_bitmap_zlib
|
||||
BBitmap*
|
||||
decompress_bitmap_zlib(const void* buffer, unsigned int size,
|
||||
BRect frame, color_space format)
|
||||
{
|
||||
BBitmap* bitmap = new BBitmap(frame, 0, format);
|
||||
if (bitmap->IsValid()) {
|
||||
if (buffer) {
|
||||
Bytef* dst = (Bytef*)bitmap->Bits();
|
||||
uLongf dstLength = bitmap->BitsLength();
|
||||
|
||||
int ret = uncompress(dst,
|
||||
&dstLength,
|
||||
(const Bytef*)buffer,
|
||||
(uLong)size);
|
||||
if (ret != Z_OK || dstLength != (uint32)bitmap->BitsLength()) {
|
||||
// decompression error!
|
||||
fprintf(stderr, "decompress_bitmap_zlib() failed "
|
||||
"- corrupted input buffer or file!\n");
|
||||
}
|
||||
} else {
|
||||
memset(bitmap->Bits(), 0, bitmap->BitsLength());
|
||||
}
|
||||
} else {
|
||||
delete bitmap;
|
||||
bitmap = NULL;
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// archive_bitmap
|
||||
status_t
|
||||
archive_bitmap(const BBitmap* bitmap, BMessage* into, const char* fieldName)
|
||||
{
|
||||
status_t ret = B_BAD_VALUE;
|
||||
if (bitmap && bitmap->IsValid() && into) {
|
||||
void* buffer;
|
||||
unsigned size;
|
||||
if (compress_bitmap_zlib(bitmap, &buffer, &size)) {
|
||||
ret = into->AddData(fieldName, B_RAW_TYPE, buffer, size);
|
||||
if (ret >= B_OK)
|
||||
ret = into->AddInt32("compression", COMPRESSION_ZLIB);
|
||||
if (ret >= B_OK)
|
||||
ret = into->AddRect("construction bounds", bitmap->Bounds());
|
||||
if (ret >= B_OK)
|
||||
ret = into->AddInt32("format", bitmap->ColorSpace());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// extract_bitmap
|
||||
status_t
|
||||
extract_bitmap(BBitmap** bitmap, const BMessage* from, const char* fieldName)
|
||||
{
|
||||
status_t ret = B_BAD_VALUE;
|
||||
if (bitmap && from) {
|
||||
*bitmap = NULL;
|
||||
// no compression (flattened BBitmap archive)
|
||||
BMessage bitmapArchive;
|
||||
if ((ret = from->FindMessage(fieldName, &bitmapArchive)) >= B_OK) {
|
||||
*bitmap = new BBitmap(&bitmapArchive);
|
||||
}
|
||||
// compression
|
||||
if (!*bitmap) {
|
||||
const void* compressedData = NULL;
|
||||
ssize_t compressedSize = 0;
|
||||
compressedData = NULL;
|
||||
compressedSize = 0;
|
||||
BRect bounds;
|
||||
color_space format;
|
||||
uint32 compression;
|
||||
if (((ret = from->FindData(fieldName,
|
||||
B_RAW_TYPE, &compressedData,
|
||||
&compressedSize)) >= B_OK
|
||||
// this is for backward compatibility
|
||||
|| (ret = from->FindData("current compressed data",
|
||||
B_RAW_TYPE, &compressedData,
|
||||
&compressedSize)) >= B_OK)
|
||||
&& (ret = from->FindRect("construction bounds",
|
||||
&bounds)) >= B_OK) {
|
||||
|
||||
// compression defaults to NONE for backward compatibility
|
||||
if (from->FindInt32("compression", (int32*)&compression) < B_OK)
|
||||
compression = COMPRESSION_NONE;
|
||||
// format defaults to B_RGBA32 for backward compatibility
|
||||
if (from->FindInt32("format", (int32*)&format) < B_OK)
|
||||
format = B_RGBA32;
|
||||
|
||||
switch (compression) {
|
||||
case COMPRESSION_ZLIB:
|
||||
*bitmap = decompress_bitmap_zlib(compressedData,
|
||||
compressedSize,
|
||||
bounds, format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (*bitmap)
|
||||
ret = (*bitmap)->InitCheck();
|
||||
else if (ret >= B_OK)
|
||||
ret = B_NO_MEMORY;
|
||||
if (ret < B_OK) {
|
||||
delete *bitmap;
|
||||
*bitmap = NULL;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef BITMAP_COMPRESSION_H
|
||||
#define BITMAP_COMPRESSION_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class BBitmap;
|
||||
class BMessage;
|
||||
|
||||
status_t
|
||||
archive_bitmap(const BBitmap* bitmap, BMessage* into, const char* fieldName);
|
||||
|
||||
status_t
|
||||
extract_bitmap(BBitmap** bitmap, const BMessage* from, const char* fieldName);
|
||||
|
||||
#endif // BITMAP_COMPRESSION_H
|
70
src/add-ons/translators/wonderbrush/support/blending.cpp
Normal file
70
src/add-ons/translators/wonderbrush/support/blending.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "blending.h"
|
||||
|
||||
#if GAMMA_BLEND
|
||||
|
||||
// speed tests done on Pentium M, 1450 MHz
|
||||
// blending two 800x600 bitmaps with "50" on each component (including alpha): 1500000 usecs
|
||||
// -"- using gamma LUT: 651000 usecs
|
||||
// -"- no use of floorf(): 572000 usecs
|
||||
|
||||
// -"- uint16 integer version: 72000 usecs
|
||||
// -"- inline: 60200 usecs
|
||||
|
||||
// for comparison:
|
||||
// -"- inline only, no LUTs, no gamma correction: 44000 usecs
|
||||
// -"- + premultiplied alpha (less MULs, no DIVs): 16500 usecs
|
||||
|
||||
|
||||
const float kGamma = 2.2;
|
||||
const float kInverseGamma = 1.0 / kGamma;
|
||||
|
||||
uint16* kGammaTable = NULL;
|
||||
uint8* kInverseGammaTable = NULL;
|
||||
|
||||
|
||||
// convert_to_gamma
|
||||
uint16
|
||||
convert_to_gamma(uint8 value)
|
||||
{
|
||||
return kGammaTable[value];
|
||||
}
|
||||
|
||||
// init_gamma_blending
|
||||
void
|
||||
init_gamma_blending()
|
||||
{
|
||||
// init LUT R'G'B' [0...255] -> RGB [0...25500]
|
||||
if (!kGammaTable)
|
||||
kGammaTable = new uint16[256];
|
||||
for (uint32 i = 0; i < 256; i++)
|
||||
kGammaTable[i] = (uint16)(powf((float)i / 255.0, kGamma) * 25500.0);
|
||||
|
||||
// init LUT RGB [0...25500] -> R'G'B' [0...255]
|
||||
if (!kInverseGammaTable)
|
||||
kInverseGammaTable = new uint8[25501];
|
||||
for (uint32 i = 0; i < 25501; i++)
|
||||
kInverseGammaTable[i] = (uint8)(powf((float)i / 25500.0, kInverseGamma) * 255.0);
|
||||
}
|
||||
|
||||
// init_gamma_blending
|
||||
void
|
||||
uninit_gamma_blending()
|
||||
{
|
||||
delete[] kGammaTable;
|
||||
kGammaTable = NULL;
|
||||
delete[] kInverseGammaTable;
|
||||
kInverseGammaTable = NULL;
|
||||
}
|
||||
|
||||
|
||||
#endif // GAMMA_BLEND
|
613
src/add-ons/translators/wonderbrush/support/blending.h
Normal file
613
src/add-ons/translators/wonderbrush/support/blending.h
Normal file
@ -0,0 +1,613 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef BLENDING_H
|
||||
#define BLENDING_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
// faster bit error version:
|
||||
//#define INT_MULT(a, b, t) ((t) = (a) * (b), ((((t) >> 8) + (t)) >> 8))
|
||||
// correct version
|
||||
#define INT_MULT(a, b, t) ((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8))
|
||||
|
||||
#define INT_LERP(p, q, a, t) ((p) + INT_MULT(a, ((q) - (p)), t))
|
||||
|
||||
#define INT_PRELERP(p, q, a, t) ((p) + (q) - INT_MULT(a, p, t))
|
||||
|
||||
|
||||
|
||||
#define GAMMA_BLEND 1
|
||||
|
||||
#if GAMMA_BLEND
|
||||
|
||||
extern uint16* kGammaTable;
|
||||
extern uint8* kInverseGammaTable;
|
||||
|
||||
void init_gamma_blending();
|
||||
void uninit_gamma_blending();
|
||||
|
||||
// blend
|
||||
inline void
|
||||
blend_gamma(uint16 b1, uint16 b2, uint16 b3, uint8 ba, // bottom components
|
||||
uint16 t1, uint16 t2, uint16 t3, uint8 ta, // top components
|
||||
uint8* d1, uint8* d2, uint8* d3, uint8* da) // dest components
|
||||
{
|
||||
if (ba == 255) {
|
||||
uint32 destAlpha = 255 - ta;
|
||||
*d1 = kInverseGammaTable[(b1 * destAlpha + t1 * ta) / 255];
|
||||
*d2 = kInverseGammaTable[(b2 * destAlpha + t2 * ta) / 255];
|
||||
*d3 = kInverseGammaTable[(b3 * destAlpha + t3 * ta) / 255];
|
||||
*da = 255;
|
||||
} else {
|
||||
uint8 alphaRest = 255 - ta;
|
||||
register uint32 alphaTemp = (65025 - alphaRest * (255 - ba));
|
||||
uint32 alphaDest = ba * alphaRest;
|
||||
uint32 alphaSrc = 255 * ta;
|
||||
*d1 = kInverseGammaTable[(b1 * alphaDest + t1 * alphaSrc) / alphaTemp];
|
||||
*d2 = kInverseGammaTable[(b2 * alphaDest + t2 * alphaSrc) / alphaTemp];
|
||||
*d3 = kInverseGammaTable[(b3 * alphaDest + t3 * alphaSrc) / alphaTemp];
|
||||
*da = alphaTemp / 255;
|
||||
}
|
||||
}
|
||||
|
||||
// blend
|
||||
inline void
|
||||
blend(uint8 b1, uint8 b2, uint8 b3, uint8 ba, // bottom components
|
||||
uint8 t1, uint8 t2, uint8 t3, uint8 ta, // top components
|
||||
uint8* d1, uint8* d2, uint8* d3, uint8* da) // dest components
|
||||
{
|
||||
// convert to linear rgb
|
||||
uint16 gt1 = kGammaTable[t1];
|
||||
uint16 gt2 = kGammaTable[t2];
|
||||
uint16 gt3 = kGammaTable[t3];
|
||||
|
||||
uint16 gb1 = kGammaTable[b1];
|
||||
uint16 gb2 = kGammaTable[b2];
|
||||
uint16 gb3 = kGammaTable[b3];
|
||||
|
||||
blend_gamma(gb1, gb2, gb3, ba,
|
||||
gt1, gt2, gt3, ta,
|
||||
d1, d2, d3, da);
|
||||
}
|
||||
|
||||
// convert_to_gamma
|
||||
//
|
||||
// converted value will be gamma corrected in the range [0...2550]
|
||||
// and can be passed on to the other functions that take uint16 components
|
||||
uint16
|
||||
convert_to_gamma(uint8 value);
|
||||
|
||||
// blend_colors_copy
|
||||
inline void
|
||||
blend_colors_copy(uint8* bottom, uint8 alpha, uint8* dest,
|
||||
uint8 c1, uint8 c2, uint8 c3,
|
||||
uint16 gc1, uint16 gc2, uint16 gc3)
|
||||
{
|
||||
if (alpha > 0) {
|
||||
if (bottom[3] == 0 || alpha == 255) {
|
||||
dest[0] = c1;
|
||||
dest[1] = c2;
|
||||
dest[2] = c3;
|
||||
dest[3] = alpha;
|
||||
} else {
|
||||
// only bottom components need to be gamma corrected
|
||||
uint16 gb1 = kGammaTable[bottom[0]];
|
||||
uint16 gb2 = kGammaTable[bottom[1]];
|
||||
uint16 gb3 = kGammaTable[bottom[2]];
|
||||
|
||||
blend_gamma(gb1, gb2, gb3, bottom[3],
|
||||
gc1, gc2, gc3, alpha,
|
||||
&dest[0], &dest[1], &dest[2], &dest[3]);
|
||||
}
|
||||
} else {
|
||||
*((uint32*)dest) = *((uint32*)bottom);
|
||||
}
|
||||
}
|
||||
|
||||
// blend_colors
|
||||
inline void
|
||||
blend_colors(uint8* bottom, uint8 alpha,
|
||||
uint8 c1, uint8 c2, uint8 c3,
|
||||
uint16 gc1, uint16 gc2, uint16 gc3)
|
||||
{
|
||||
if (alpha > 0) {
|
||||
if (bottom[3] == 0 || alpha == 255) {
|
||||
bottom[0] = c1;
|
||||
bottom[1] = c2;
|
||||
bottom[2] = c3;
|
||||
bottom[3] = alpha;
|
||||
} else {
|
||||
// only bottom components need to be gamma corrected
|
||||
uint16 gb1 = kGammaTable[bottom[0]];
|
||||
uint16 gb2 = kGammaTable[bottom[1]];
|
||||
uint16 gb3 = kGammaTable[bottom[2]];
|
||||
|
||||
blend_gamma(gb1, gb2, gb3, bottom[3],
|
||||
gc1, gc2, gc3, alpha,
|
||||
&bottom[0], &bottom[1], &bottom[2], &bottom[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// blend_colors_copy
|
||||
inline void
|
||||
blend_colors_copy(uint8* bottom, uint8 alpha, uint8* dest,
|
||||
uint8 c1, uint8 c2, uint8 c3)
|
||||
{
|
||||
if (alpha > 0) {
|
||||
if (bottom[3] == 0 || alpha == 255) {
|
||||
dest[0] = c1;
|
||||
dest[1] = c2;
|
||||
dest[2] = c3;
|
||||
dest[3] = alpha;
|
||||
} else {
|
||||
blend(bottom[0], bottom[1], bottom[2], bottom[3],
|
||||
c1, c2, c3, alpha,
|
||||
&dest[0], &dest[1], &dest[2], &dest[3]);
|
||||
}
|
||||
} else {
|
||||
*((uint32*)dest) = *((uint32*)bottom);
|
||||
}
|
||||
}
|
||||
|
||||
// blend_colors
|
||||
inline void
|
||||
blend_colors(uint8* bottom, uint8 alpha, uint8 c1, uint8 c2, uint8 c3)
|
||||
{
|
||||
if (alpha > 0) {
|
||||
if (bottom[3] == 0 || alpha == 255) {
|
||||
bottom[0] = c1;
|
||||
bottom[1] = c2;
|
||||
bottom[2] = c3;
|
||||
bottom[3] = alpha;
|
||||
} else {
|
||||
blend(bottom[0], bottom[1], bottom[2], bottom[3],
|
||||
c1, c2, c3, alpha,
|
||||
&bottom[0], &bottom[1], &bottom[2], &bottom[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// blend_colors
|
||||
inline void
|
||||
blend_colors(uint8* bottom, uint8* source, uint8 alphaOverride)
|
||||
{
|
||||
uint8 alpha = (source[3] * alphaOverride) / 255;
|
||||
if (alpha > 0) {
|
||||
if (bottom[3] == 0 || alpha == 255) {
|
||||
bottom[0] = source[0];
|
||||
bottom[1] = source[1];
|
||||
bottom[2] = source[2];
|
||||
bottom[3] = alpha;
|
||||
} else {
|
||||
blend(bottom[0], bottom[1], bottom[2], bottom[3],
|
||||
source[0], source[1], source[2], alpha,
|
||||
&bottom[0], &bottom[1], &bottom[2], &bottom[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// blend_colors
|
||||
inline void
|
||||
blend_colors(uint8* bottom, uint8* source)
|
||||
{
|
||||
if (source[3] > 0) {
|
||||
if (bottom[3] == 0 || source[3] == 255) {
|
||||
bottom[0] = source[0];
|
||||
bottom[1] = source[1];
|
||||
bottom[2] = source[2];
|
||||
bottom[3] = source[3];
|
||||
} else {
|
||||
blend(bottom[0], bottom[1], bottom[2], bottom[3],
|
||||
source[0], source[1], source[2], source[3],
|
||||
&bottom[0], &bottom[1], &bottom[2], &bottom[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// blend_colors_copy
|
||||
inline void
|
||||
blend_colors_copy(uint8* dest, uint8* bottom, uint8* top)
|
||||
{
|
||||
if (bottom[3] == 0 || top[3] == 255) {
|
||||
dest[0] = top[0];
|
||||
dest[1] = top[1];
|
||||
dest[2] = top[2];
|
||||
dest[3] = top[3];
|
||||
} else {
|
||||
blend(bottom[0], bottom[1], bottom[2], bottom[3],
|
||||
top[0], top[1], top[2], top[3],
|
||||
&dest[0], &dest[1], &dest[2], &dest[3]);
|
||||
}
|
||||
}
|
||||
|
||||
// blend_pixels
|
||||
inline void
|
||||
blend_pixels(uint8* bottom, uint8* top, uint8 alpha)
|
||||
{
|
||||
if (alpha > 0) {
|
||||
if (alpha == 255) {
|
||||
bottom[0] = top[0];
|
||||
bottom[1] = top[1];
|
||||
bottom[2] = top[2];
|
||||
bottom[3] = top[3];
|
||||
} else {
|
||||
// convert to linear rgb
|
||||
uint16 t1 = kGammaTable[top[0]];
|
||||
uint16 t2 = kGammaTable[top[1]];
|
||||
uint16 t3 = kGammaTable[top[2]];
|
||||
uint16 b1 = kGammaTable[bottom[0]];
|
||||
uint16 b2 = kGammaTable[bottom[1]];
|
||||
uint16 b3 = kGammaTable[bottom[2]];
|
||||
|
||||
uint8 mergeAlpha = bottom[3] ? (top[3] * alpha) / 255 : 255;
|
||||
uint8 invAlpha = 255 - mergeAlpha;
|
||||
bottom[0] = kInverseGammaTable[(b1 * invAlpha + t1 * mergeAlpha) / 255];
|
||||
bottom[1] = kInverseGammaTable[(b2 * invAlpha + t2 * mergeAlpha) / 255];
|
||||
bottom[2] = kInverseGammaTable[(b3 * invAlpha + t3 * mergeAlpha) / 255];
|
||||
bottom[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// blend_pixels_copy
|
||||
inline void
|
||||
blend_pixels_copy(uint8* bottom, uint8* top, uint8* dest, uint8 alpha)
|
||||
{
|
||||
if (alpha > 0) {
|
||||
if (alpha == 255) {
|
||||
dest[0] = top[0];
|
||||
dest[1] = top[1];
|
||||
dest[2] = top[2];
|
||||
dest[3] = top[3];
|
||||
} else {
|
||||
// convert to linear rgb
|
||||
uint16 t1 = kGammaTable[top[0]];
|
||||
uint16 t2 = kGammaTable[top[1]];
|
||||
uint16 t3 = kGammaTable[top[2]];
|
||||
uint16 b1 = kGammaTable[bottom[0]];
|
||||
uint16 b2 = kGammaTable[bottom[1]];
|
||||
uint16 b3 = kGammaTable[bottom[2]];
|
||||
|
||||
uint8 mergeAlpha = bottom[3] ? (top[3] * alpha) / 255 : 255;
|
||||
uint8 invAlpha = 255 - mergeAlpha;
|
||||
dest[0] = kInverseGammaTable[(b1 * invAlpha + t1 * mergeAlpha) / 255];
|
||||
dest[1] = kInverseGammaTable[(b2 * invAlpha + t2 * mergeAlpha) / 255];
|
||||
dest[2] = kInverseGammaTable[(b3 * invAlpha + t3 * mergeAlpha) / 255];
|
||||
dest[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
|
||||
}
|
||||
} else {
|
||||
dest[0] = bottom[0];
|
||||
dest[1] = bottom[1];
|
||||
dest[2] = bottom[2];
|
||||
dest[3] = bottom[3];
|
||||
}
|
||||
}
|
||||
|
||||
// blend_pixels_overlay
|
||||
inline void
|
||||
blend_pixels_overlay(uint8* bottom, uint8* top, uint8 alphaOverride)
|
||||
{
|
||||
uint8 alpha = (top[3] * alphaOverride) / 255;
|
||||
if (alpha > 0) {
|
||||
if (alpha == 255) {
|
||||
bottom[0] = top[0];
|
||||
bottom[1] = top[1];
|
||||
bottom[2] = top[2];
|
||||
bottom[3] = top[3];
|
||||
} else {
|
||||
// convert to linear rgb
|
||||
uint16 t1 = kGammaTable[top[0]];
|
||||
uint16 t2 = kGammaTable[top[1]];
|
||||
uint16 t3 = kGammaTable[top[2]];
|
||||
uint16 b1 = kGammaTable[bottom[0]];
|
||||
uint16 b2 = kGammaTable[bottom[1]];
|
||||
uint16 b3 = kGammaTable[bottom[2]];
|
||||
|
||||
uint8 mergeAlpha = bottom[3] ? alpha : 255;
|
||||
uint8 invAlpha = 255 - mergeAlpha;
|
||||
bottom[0] = kInverseGammaTable[(b1 * invAlpha + t1 * mergeAlpha) / 255];
|
||||
bottom[1] = kInverseGammaTable[(b2 * invAlpha + t2 * mergeAlpha) / 255];
|
||||
bottom[2] = kInverseGammaTable[(b3 * invAlpha + t3 * mergeAlpha) / 255];
|
||||
bottom[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// blend_pixels_overlay_copy
|
||||
inline void
|
||||
blend_pixels_overlay_copy(uint8* bottom, uint8* top, uint8* dest, uint8 alphaOverride)
|
||||
{
|
||||
uint8 alpha = (top[3] * alphaOverride) / 255;
|
||||
if (alpha > 0) {
|
||||
if (alpha == 255) {
|
||||
dest[0] = top[0];
|
||||
dest[1] = top[1];
|
||||
dest[2] = top[2];
|
||||
dest[3] = top[3];
|
||||
} else {
|
||||
// convert to linear rgb
|
||||
uint16 t1 = kGammaTable[top[0]];
|
||||
uint16 t2 = kGammaTable[top[1]];
|
||||
uint16 t3 = kGammaTable[top[2]];
|
||||
uint16 b1 = kGammaTable[bottom[0]];
|
||||
uint16 b2 = kGammaTable[bottom[1]];
|
||||
uint16 b3 = kGammaTable[bottom[2]];
|
||||
|
||||
uint8 mergeAlpha = bottom[3] ? alpha : 255;
|
||||
uint8 invAlpha = 255 - mergeAlpha;
|
||||
dest[0] = kInverseGammaTable[(b1 * invAlpha + t1 * mergeAlpha) / 255];
|
||||
dest[1] = kInverseGammaTable[(b2 * invAlpha + t2 * mergeAlpha) / 255];
|
||||
dest[2] = kInverseGammaTable[(b3 * invAlpha + t3 * mergeAlpha) / 255];
|
||||
dest[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
|
||||
}
|
||||
} else {
|
||||
dest[0] = bottom[0];
|
||||
dest[1] = bottom[1];
|
||||
dest[2] = bottom[2];
|
||||
dest[3] = bottom[3];
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#else // GAMMA_BLEND
|
||||
|
||||
// blend_colors_copy
|
||||
inline void
|
||||
blend_colors_copy(uint8* bottom, uint8 alpha, uint8* dest,
|
||||
uint8 c1, uint8 c2, uint8 c3)
|
||||
{
|
||||
if (alpha > 0) {
|
||||
if (bottom[3] == 0 || alpha == 255) {
|
||||
dest[0] = c1;
|
||||
dest[1] = c2;
|
||||
dest[2] = c3;
|
||||
dest[3] = alpha;
|
||||
} else {
|
||||
if (bottom[3] == 255) {
|
||||
uint32 destAlpha = 255 - alpha;
|
||||
dest[0] = (uint8)((bottom[0] * destAlpha + c1 * alpha) / 255);
|
||||
dest[1] = (uint8)((bottom[1] * destAlpha + c2 * alpha) / 255);
|
||||
dest[2] = (uint8)((bottom[2] * destAlpha + c3 * alpha) / 255);
|
||||
dest[3] = 255;
|
||||
} else {
|
||||
uint8 alphaRest = 255 - alpha;
|
||||
uint32 alphaTemp = (65025 - alphaRest * (255 - bottom[3]));
|
||||
uint32 alphaDest = bottom[3] * alphaRest;
|
||||
uint32 alphaSrc = 255 * alpha;
|
||||
dest[0] = (bottom[0] * alphaDest + c1 * alphaSrc) / alphaTemp;
|
||||
dest[1] = (bottom[1] * alphaDest + c2 * alphaSrc) / alphaTemp;
|
||||
dest[2] = (bottom[2] * alphaDest + c3 * alphaSrc) / alphaTemp;
|
||||
dest[3] = alphaTemp / 255;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*((uint32*)dest) = *((uint32*)bottom);
|
||||
}
|
||||
}
|
||||
|
||||
// blend_colors
|
||||
inline void
|
||||
blend_colors(uint8* bottom, uint8 alpha, uint8 c1, uint8 c2, uint8 c3)
|
||||
{
|
||||
if (alpha > 0) {
|
||||
if (bottom[3] == 0 || alpha == 255) {
|
||||
bottom[0] = c1;
|
||||
bottom[1] = c2;
|
||||
bottom[2] = c3;
|
||||
bottom[3] = alpha;
|
||||
} else {
|
||||
if (bottom[3] == 255) {
|
||||
uint32 destAlpha = 255 - alpha;
|
||||
bottom[0] = (uint8)((bottom[0] * destAlpha + c1 * alpha) / 255);
|
||||
bottom[1] = (uint8)((bottom[1] * destAlpha + c2 * alpha) / 255);
|
||||
bottom[2] = (uint8)((bottom[2] * destAlpha + c3 * alpha) / 255);
|
||||
} else {
|
||||
uint8 alphaRest = 255 - alpha;
|
||||
uint32 alphaTemp = (65025 - alphaRest * (255 - bottom[3]));
|
||||
uint32 alphaDest = bottom[3] * alphaRest;
|
||||
uint32 alphaSrc = 255 * alpha;
|
||||
bottom[0] = (bottom[0] * alphaDest + c1 * alphaSrc) / alphaTemp;
|
||||
bottom[1] = (bottom[1] * alphaDest + c2 * alphaSrc) / alphaTemp;
|
||||
bottom[2] = (bottom[2] * alphaDest + c3 * alphaSrc) / alphaTemp;
|
||||
bottom[3] = alphaTemp / 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// blend_colors
|
||||
inline void
|
||||
blend_colors(uint8* bottom, uint8* source, uint8 alphaOverride)
|
||||
{
|
||||
uint8 alpha = (source[3] * alphaOverride) / 255;
|
||||
if (alpha > 0) {
|
||||
if (bottom[3] == 0 || alpha == 255) {
|
||||
bottom[0] = source[0];
|
||||
bottom[1] = source[1];
|
||||
bottom[2] = source[2];
|
||||
bottom[3] = alpha;
|
||||
} else {
|
||||
if (bottom[3] == 255) {
|
||||
uint32 destAlpha = 255 - alpha;
|
||||
bottom[0] = (uint8)((bottom[0] * destAlpha + source[0] * alpha) / 255);
|
||||
bottom[1] = (uint8)((bottom[1] * destAlpha + source[1] * alpha) / 255);
|
||||
bottom[2] = (uint8)((bottom[2] * destAlpha + source[2] * alpha) / 255);
|
||||
} else {
|
||||
uint8 alphaRest = 255 - alpha;
|
||||
uint32 alphaTemp = (65025 - alphaRest * (255 - bottom[3]));
|
||||
uint32 alphaDest = bottom[3] * alphaRest;
|
||||
uint32 alphaSrc = 255 * alpha;
|
||||
bottom[0] = (bottom[0] * alphaDest + source[0] * alphaSrc) / alphaTemp;
|
||||
bottom[1] = (bottom[1] * alphaDest + source[1] * alphaSrc) / alphaTemp;
|
||||
bottom[2] = (bottom[2] * alphaDest + source[2] * alphaSrc) / alphaTemp;
|
||||
bottom[3] = alphaTemp / 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// blend_colors
|
||||
inline void
|
||||
blend_colors(uint8* bottom, uint8* source)
|
||||
{
|
||||
if (source[3] > 0) {
|
||||
if (bottom[3] == 0 || source[3] == 255) {
|
||||
bottom[0] = source[0];
|
||||
bottom[1] = source[1];
|
||||
bottom[2] = source[2];
|
||||
bottom[3] = source[3];
|
||||
} else {
|
||||
if (bottom[3] == 255) {
|
||||
uint32 destAlpha = 255 - source[3];
|
||||
bottom[0] = (uint8)((bottom[0] * destAlpha + source[0] * source[3]) / 255);
|
||||
bottom[1] = (uint8)((bottom[1] * destAlpha + source[1] * source[3]) / 255);
|
||||
bottom[2] = (uint8)((bottom[2] * destAlpha + source[2] * source[3]) / 255);
|
||||
} else {
|
||||
uint8 alphaRest = 255 - source[3];
|
||||
uint32 alphaTemp = (65025 - alphaRest * (255 - bottom[3]));
|
||||
uint32 alphaDest = bottom[3] * alphaRest;
|
||||
uint32 alphaSrc = 255 * source[3];
|
||||
bottom[0] = (bottom[0] * alphaDest + source[0] * alphaSrc) / alphaTemp;
|
||||
bottom[1] = (bottom[1] * alphaDest + source[1] * alphaSrc) / alphaTemp;
|
||||
bottom[2] = (bottom[2] * alphaDest + source[2] * alphaSrc) / alphaTemp;
|
||||
bottom[3] = alphaTemp / 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// blend_colors_copy
|
||||
inline void
|
||||
blend_colors_copy(uint8* dest, uint8* bottom, uint8* top)
|
||||
{
|
||||
if (bottom[3] == 0 || top[3] == 255) {
|
||||
dest[0] = top[0];
|
||||
dest[1] = top[1];
|
||||
dest[2] = top[2];
|
||||
dest[3] = top[3];
|
||||
} else {
|
||||
if (bottom[3] == 255) {
|
||||
uint32 destAlpha = 255 - top[3];
|
||||
dest[0] = (uint8)((bottom[0] * destAlpha + top[0] * top[3]) / 255);
|
||||
dest[1] = (uint8)((bottom[1] * destAlpha + top[1] * top[3]) / 255);
|
||||
dest[2] = (uint8)((bottom[2] * destAlpha + top[2] * top[3]) / 255);
|
||||
dest[3] = 255;
|
||||
} else {
|
||||
uint8 alphaRest = 255 - top[3];
|
||||
uint32 alphaTemp = (65025 - alphaRest * (255 - bottom[3]));
|
||||
uint32 alphaDest = bottom[3] * alphaRest;
|
||||
uint32 alphaSrc = 255 * top[3];
|
||||
dest[0] = (bottom[0] * alphaDest + top[0] * alphaSrc) / alphaTemp;
|
||||
dest[1] = (bottom[1] * alphaDest + top[1] * alphaSrc) / alphaTemp;
|
||||
dest[2] = (bottom[2] * alphaDest + top[2] * alphaSrc) / alphaTemp;
|
||||
dest[3] = alphaTemp / 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// blend_pixels
|
||||
inline void
|
||||
blend_pixels(uint8* bottom, uint8* top, uint8 alpha)
|
||||
{
|
||||
if (alpha > 0) {
|
||||
if (alpha == 255) {
|
||||
bottom[0] = top[0];
|
||||
bottom[1] = top[1];
|
||||
bottom[2] = top[2];
|
||||
bottom[3] = top[3];
|
||||
} else {
|
||||
uint8 mergeAlpha = bottom[3] ? (top[3] * alpha) / 255 : 255;
|
||||
uint8 invAlpha = 255 - mergeAlpha;
|
||||
bottom[0] = (bottom[0] * invAlpha + top[0] * mergeAlpha) / 255;
|
||||
bottom[1] = (bottom[1] * invAlpha + top[1] * mergeAlpha) / 255;
|
||||
bottom[2] = (bottom[2] * invAlpha + top[2] * mergeAlpha) / 255;
|
||||
bottom[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// blend_pixels_copy
|
||||
inline void
|
||||
blend_pixels_copy(uint8* bottom, uint8* top, uint8* dest, uint8 alpha)
|
||||
{
|
||||
if (alpha > 0) {
|
||||
if (alpha == 255) {
|
||||
dest[0] = top[0];
|
||||
dest[1] = top[1];
|
||||
dest[2] = top[2];
|
||||
dest[3] = top[3];
|
||||
} else {
|
||||
uint8 mergeAlpha = bottom[3] ? (top[3] * alpha) / 255 : 255;
|
||||
uint8 invAlpha = 255 - mergeAlpha;
|
||||
dest[0] = (bottom[0] * invAlpha + top[0] * mergeAlpha) / 255;
|
||||
dest[1] = (bottom[1] * invAlpha + top[1] * mergeAlpha) / 255;
|
||||
dest[2] = (bottom[2] * invAlpha + top[2] * mergeAlpha) / 255;
|
||||
dest[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
|
||||
}
|
||||
} else {
|
||||
dest[0] = bottom[0];
|
||||
dest[1] = bottom[1];
|
||||
dest[2] = bottom[2];
|
||||
dest[3] = bottom[3];
|
||||
}
|
||||
}
|
||||
|
||||
// blend_pixels_overlay
|
||||
inline void
|
||||
blend_pixels_overlay(uint8* bottom, uint8* top, uint8 alphaOverride)
|
||||
{
|
||||
uint8 alpha = (top[3] * alphaOverride) / 255;
|
||||
if (alpha > 0) {
|
||||
if (alpha == 255) {
|
||||
bottom[0] = top[0];
|
||||
bottom[1] = top[1];
|
||||
bottom[2] = top[2];
|
||||
bottom[3] = top[3];
|
||||
} else {
|
||||
uint8 mergeAlpha = bottom[3] ? alpha : 255;
|
||||
uint8 invAlpha = 255 - mergeAlpha;
|
||||
bottom[0] = (bottom[0] * invAlpha + top[0] * mergeAlpha) / 255;
|
||||
bottom[1] = (bottom[1] * invAlpha + top[1] * mergeAlpha) / 255;
|
||||
bottom[2] = (bottom[2] * invAlpha + top[2] * mergeAlpha) / 255;
|
||||
bottom[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// blend_pixels_overlay_copy
|
||||
inline void
|
||||
blend_pixels_overlay_copy(uint8* bottom, uint8* top, uint8* dest, uint8 alphaOverride)
|
||||
{
|
||||
uint8 alpha = (top[3] * alphaOverride) / 255;
|
||||
if (alpha > 0) {
|
||||
if (alpha == 255) {
|
||||
dest[0] = top[0];
|
||||
dest[1] = top[1];
|
||||
dest[2] = top[2];
|
||||
dest[3] = top[3];
|
||||
} else {
|
||||
uint8 mergeAlpha = bottom[3] ? alpha : 255;
|
||||
uint8 invAlpha = 255 - mergeAlpha;
|
||||
dest[0] = (bottom[0] * invAlpha + top[0] * mergeAlpha) / 255;
|
||||
dest[1] = (bottom[1] * invAlpha + top[1] * mergeAlpha) / 255;
|
||||
dest[2] = (bottom[2] * invAlpha + top[2] * mergeAlpha) / 255;
|
||||
dest[3] = (bottom[3] * (255 - alpha) + top[3] * alpha) / 255;
|
||||
}
|
||||
} else {
|
||||
dest[0] = bottom[0];
|
||||
dest[1] = bottom[1];
|
||||
dest[2] = bottom[2];
|
||||
dest[3] = bottom[3];
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GAMMA_BLEND
|
||||
|
||||
#endif // BLENDING_H
|
200
src/add-ons/translators/wonderbrush/support/lab_convert.cpp
Normal file
200
src/add-ons/translators/wonderbrush/support/lab_convert.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "support.h"
|
||||
|
||||
#include "lab_convert.h"
|
||||
|
||||
#define GAMMA_ZERO_ENTRIES 256
|
||||
#define GAMMA_ENTRIES 10240
|
||||
#define GAMMA_MAX_ENTRIES 256
|
||||
#define GAMMA_TOTAL_ENTRIES GAMMA_ZERO_ENTRIES + GAMMA_ENTRIES + GAMMA_MAX_ENTRIES
|
||||
|
||||
// init_gamma_table
|
||||
uint8*
|
||||
init_gamma_table()
|
||||
{
|
||||
uint8* table = new uint8[GAMMA_TOTAL_ENTRIES];
|
||||
for (int32 i = 0; i < GAMMA_ZERO_ENTRIES; i++)
|
||||
table[i] = 0;
|
||||
for (int32 i = 0; i < GAMMA_ENTRIES; i++)
|
||||
table[i + GAMMA_ZERO_ENTRIES] = (uint8)(pow((float)i / (float)(GAMMA_ENTRIES - 1), 0.4) * 255.0 + 0.5);
|
||||
for (int32 i = 0; i < GAMMA_MAX_ENTRIES; i++)
|
||||
table[i + GAMMA_ZERO_ENTRIES + GAMMA_ENTRIES] = 255;
|
||||
return table;
|
||||
}
|
||||
|
||||
// init_linear_table
|
||||
float*
|
||||
init_linear_table()
|
||||
{
|
||||
float* table = new float[256];
|
||||
for (int32 i = 0; i < 256; i++)
|
||||
table[i] = pow((float)i / 255.0, 2.5);
|
||||
return table;
|
||||
}
|
||||
|
||||
// conversion from RGB (0...255) to linear and normalized RGB (0...1)
|
||||
static uint8* gammaTable = init_gamma_table();
|
||||
static float* linearTable = init_linear_table();
|
||||
|
||||
// matrix entries: XYZ -> RGB (709 RGB, D65 Whitepoint)
|
||||
/*const float Rx = 3.240479;
|
||||
const float Ry = -1.537150;
|
||||
const float Rz = -0.498535;
|
||||
const float Gx = -0.969256;
|
||||
const float Gy = 1.875992;
|
||||
const float Gz = 0.041556;
|
||||
const float Bx = 0.055648;
|
||||
const float By = -0.204043;
|
||||
const float Bz = 1.057311;*/
|
||||
|
||||
// matrix entries: XYZ -> sRGB (D65 Whitepoint)
|
||||
const float Rx = 3.24071;
|
||||
const float Ry = -1.53726;
|
||||
const float Rz = -0.498571;
|
||||
const float Gx = -0.969258;
|
||||
const float Gy = 1.87599;
|
||||
const float Gz = 0.0415557;
|
||||
const float Bx = 0.0556352;
|
||||
const float By = -0.203996;
|
||||
const float Bz = 1.05707;
|
||||
|
||||
|
||||
// matrix entries scaled: XYZ(0...1) -> RGB(0...255)
|
||||
const float RX = Rx * 255;
|
||||
const float RY = Ry * 255;
|
||||
const float RZ = Rz * 255;
|
||||
const float GX = Gx * 255;
|
||||
const float GY = Gy * 255;
|
||||
const float GZ = Gz * 255;
|
||||
const float BX = Bx * 255;
|
||||
const float BY = By * 255;
|
||||
const float BZ = Bz * 255;
|
||||
|
||||
// matrix etries: RGB -> XYZ
|
||||
/*const float Xr = 0.412453;
|
||||
const float Xg = 0.357580;
|
||||
const float Xb = 0.189423;
|
||||
const float Yr = 0.212671;
|
||||
const float Yg = 0.715160;
|
||||
const float Yb = 0.072169;
|
||||
const float Zr = 0.019334;
|
||||
const float Zg = 0.119193;
|
||||
const float Zb = 0.950227;*/
|
||||
|
||||
// matrix etries: sRGB -> XYZ (D65 Whitepoint)
|
||||
const float Xr = 0.412424;
|
||||
const float Xg = 0.357579;
|
||||
const float Xb = 0.180464;
|
||||
const float Yr = 0.212656;
|
||||
const float Yg = 0.715158;
|
||||
const float Yb = 0.0721856;
|
||||
const float Zr = 0.0193324;
|
||||
const float Zg = 0.119193;
|
||||
const float Zb = 0.950444;
|
||||
|
||||
// matrix entries scaled: RGB(0...255) -> XYZ(0...1)
|
||||
const float XR = Xr / 255;
|
||||
const float XG = Xg / 255;
|
||||
const float XB = Xb / 255;
|
||||
const float YR = Yr / 255;
|
||||
const float YG = Yg / 255;
|
||||
const float YB = Yb / 255;
|
||||
const float ZR = Zr / 255;
|
||||
const float ZG = Zg / 255;
|
||||
const float ZB = Zb / 255;
|
||||
|
||||
// white point
|
||||
const float Xn = Xr + Xg + Xb;
|
||||
const float Yn = Yr + Yg + Yb;
|
||||
const float Zn = Zr + Zg + Zb;
|
||||
|
||||
// matrix entries scaled and white point normalized: RGB(0...255) -> XYZ(0...1/WP)
|
||||
const float XRn = Xr / Xn;
|
||||
const float XGn = Xg / Xn;
|
||||
const float XBn = Xb / Xn;
|
||||
const float YRn = Yr / Yn;
|
||||
const float YGn = Yg / Yn;
|
||||
const float YBn = Yb / Yn;
|
||||
const float ZRn = Zr / Zn;
|
||||
const float ZGn = Zg / Zn;
|
||||
const float ZBn = Zb / Zn;
|
||||
|
||||
// lab2rgb
|
||||
void
|
||||
lab2rgb(float L, float a, float b, uint8& R, uint8& G, uint8& B)
|
||||
{
|
||||
float P = (L + 16) / 116;
|
||||
float Pa500 = P + a / 500;
|
||||
float Pb200 = P - b / 200;
|
||||
float X = Xn * Pa500 * Pa500 * Pa500;
|
||||
float Y = Yn * P * P * P;
|
||||
float Z = Zn * Pb200 * Pb200 * Pb200;
|
||||
/* float linearR = max_c(0.0, min_c(1.0, Rx * X + Ry * Y + Rz * Z));
|
||||
float linearG = max_c(0.0, min_c(1.0, Gx * X + Gy * Y + Gz * Z));
|
||||
float linearB = max_c(0.0, min_c(1.0, Bx * X + By * Y + Bz * Z));
|
||||
R = (uint8)(pow(linearR, 0.4) * 255.0 + 0.5);
|
||||
G = (uint8)(pow(linearG, 0.4) * 255.0 + 0.5);
|
||||
B = (uint8)(pow(linearB, 0.4) * 255.0 + 0.5);*/
|
||||
float linearR = Rx * X + Ry * Y + Rz * Z;
|
||||
float linearG = Gx * X + Gy * Y + Gz * Z;
|
||||
float linearB = Bx * X + By * Y + Bz * Z;
|
||||
R = (uint8)constrain_int32_0_255((int32)(pow(linearR, 0.4) * 255.0 + 0.5));
|
||||
G = (uint8)constrain_int32_0_255((int32)(pow(linearG, 0.4) * 255.0 + 0.5));
|
||||
B = (uint8)constrain_int32_0_255((int32)(pow(linearB, 0.4) * 255.0 + 0.5));
|
||||
/* float linearR = Rx * X + Ry * Y + Rz * Z;
|
||||
float linearG = Gx * X + Gy * Y + Gz * Z;
|
||||
float linearB = Bx * X + By * Y + Bz * Z;
|
||||
R = gammaTable[(uint32)(linearR * (GAMMA_ENTRIES - 1) + 0.5) + GAMMA_ZERO_ENTRIES];
|
||||
G = gammaTable[(uint32)(linearG * (GAMMA_ENTRIES - 1) + 0.5) + GAMMA_ZERO_ENTRIES];
|
||||
B = gammaTable[(uint32)(linearB * (GAMMA_ENTRIES - 1) + 0.5) + GAMMA_ZERO_ENTRIES];*/
|
||||
}
|
||||
|
||||
inline float
|
||||
f(float t)
|
||||
{
|
||||
if (t > 0.008856)
|
||||
return pow(t, 1.0 / 3.0);
|
||||
return 7.787 * t + 16.0 / 116;
|
||||
}
|
||||
|
||||
// rgb2lab
|
||||
void
|
||||
rgb2lab(uint8 R, uint8 G, uint8 B, float& L, float& a, float& b)
|
||||
{
|
||||
/* float linearR = pow((float)R / 255.0, 2.5);
|
||||
float linearG = pow((float)G / 255.0, 2.5);
|
||||
float linearB = pow((float)B / 255.0, 2.5);*/
|
||||
float linearR = linearTable[R];
|
||||
float linearG = linearTable[G];
|
||||
float linearB = linearTable[B];
|
||||
float Xq = XRn * linearR + XGn * linearG + XBn * linearB; // == X/Xn
|
||||
float Yq = YRn * linearR + YGn * linearG + YBn * linearB; // == Y/Yn
|
||||
float Zq = ZRn * linearR + ZGn * linearG + ZBn * linearB; // == Z/Zn
|
||||
if (Yq > 0.008856)
|
||||
L = 116.0 * pow(Yq, 1.0 / 3.0) - 16;
|
||||
else
|
||||
L = 903.3 * Yq;
|
||||
a = 500 * (f(Xq) - f(Yq));
|
||||
b = 200 * (f(Yq) - f(Zq));
|
||||
}
|
||||
|
||||
// replace_luminance
|
||||
void
|
||||
replace_luminance(uint8& r1, uint8& g1, uint8& b1, uint8 r2, uint8 g2, uint8 b2)
|
||||
{
|
||||
float CIEL1, CIEa1, CIEb1, CIEL2;//, CIEa2, CIEb2;
|
||||
rgb2lab(r1, g1, b1, CIEL1, CIEa1, CIEb1);
|
||||
// rgb2lab(r2, g2, b2, CIEL2, CIEa2, CIEb2);
|
||||
CIEL2 = ((linearTable[r2] + linearTable[g2] + linearTable[b2]) / 3.0) * 100.0;
|
||||
lab2rgb(CIEL2, CIEa1, CIEb1, r1, g1, b1);
|
||||
}
|
41
src/add-ons/translators/wonderbrush/support/lab_convert.h
Normal file
41
src/add-ons/translators/wonderbrush/support/lab_convert.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef LAB_CONVERT_H
|
||||
#define LAB_CONVERT_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
void lab2rgb(float L, float a, float b, uint8& R, uint8& G, uint8& B);
|
||||
|
||||
// lab2rgb
|
||||
inline void
|
||||
lab2rgb(uint8 L, uint8 a, uint8 b, uint8& R, uint8& G, uint8& B)
|
||||
{
|
||||
float CIEL = ((float)L / 255.0) * 100.0;
|
||||
float CIEa = ((float)a - 128.0);
|
||||
float CIEb = ((float)b - 128.0);
|
||||
lab2rgb(CIEL, CIEa, CIEb, R, G, B);
|
||||
}
|
||||
|
||||
void rgb2lab(uint8 R, uint8 G, uint8 B, float& L, float& a, float& b);
|
||||
|
||||
// rgb2lab
|
||||
inline void
|
||||
rgb2lab(uint8 R, uint8 G, uint8 B, uint8& L, uint8& a, uint8& b)
|
||||
{
|
||||
float CIEL, CIEa, CIEb;
|
||||
rgb2lab(R, G, B, CIEL, CIEa, CIEb);
|
||||
L = uint8((CIEL / 100.0) * 255.0);
|
||||
a = uint8(CIEa + 128);
|
||||
b = uint8(CIEb + 128);
|
||||
}
|
||||
|
||||
void replace_luminance(uint8& r1, uint8& g1, uint8& b1, uint8 r2, uint8 g2, uint8 b2);
|
||||
|
||||
#endif // LAB_CONVERT_H
|
58
src/add-ons/translators/wonderbrush/support/support.h
Normal file
58
src/add-ons/translators/wonderbrush/support/support.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef SUPPORT_H
|
||||
#define SUPPORT_H
|
||||
|
||||
#include <Rect.h>
|
||||
|
||||
// constrain
|
||||
inline void
|
||||
constrain(float& value, float min, float max)
|
||||
{
|
||||
if (value < min)
|
||||
value = min;
|
||||
if (value > max)
|
||||
value = max;
|
||||
}
|
||||
|
||||
// constrain_int32_0_255_asm
|
||||
inline int32
|
||||
constrain_int32_0_255_asm(int32 value) {
|
||||
asm("movl $0, %%ecx;
|
||||
movl $255, %%edx;
|
||||
cmpl %%ecx, %%eax;
|
||||
cmovl %%ecx, %%eax;
|
||||
cmpl %%edx, %%eax;
|
||||
cmovg %%edx, %%eax"
|
||||
: "=a" (value)
|
||||
: "a" (value)
|
||||
: "%ecx", "%edx" );
|
||||
return value;
|
||||
}
|
||||
|
||||
inline int32
|
||||
constrain_int32_0_255_c(int32 value) {
|
||||
return max_c(0, min_c(255, value));
|
||||
}
|
||||
|
||||
#define constrain_int32_0_255 constrain_int32_0_255_asm
|
||||
|
||||
// rect_to_int
|
||||
inline void
|
||||
rect_to_int(BRect r,
|
||||
int32& left, int32& top, int32& right, int32& bottom)
|
||||
{
|
||||
left = (int32)floorf(r.left);
|
||||
top = (int32)floorf(r.top);
|
||||
right = (int32)ceilf(r.right);
|
||||
bottom = (int32)ceilf(r.bottom);
|
||||
}
|
||||
|
||||
|
||||
# endif // SUPPORT_H
|
Loading…
x
Reference in New Issue
Block a user