add SkLerpXfermode
BUG= R=bsalomon@google.com Review URL: https://codereview.chromium.org/15602003 git-svn-id: http://skia.googlecode.com/svn/trunk@9229 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
edef4aa8d8
commit
b83cb9bf89
64
gm/lerpmode.cpp
Normal file
64
gm/lerpmode.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "gm.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkLerpXfermode.h"
|
||||
|
||||
static void show_circlelayers(SkCanvas* canvas, SkXfermode* mode) {
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
SkRect r, bounds = { 10, 10, 110, 110 };
|
||||
|
||||
r = bounds;
|
||||
r.fRight = bounds.centerX();
|
||||
canvas->drawRect(r, paint);
|
||||
|
||||
canvas->saveLayer(&bounds, NULL);
|
||||
|
||||
paint.setColor(0x80FF0000);
|
||||
r = bounds;
|
||||
r.inset(20, 0);
|
||||
canvas->drawOval(r, paint);
|
||||
|
||||
paint.setColor(0x800000FF);
|
||||
r = bounds;
|
||||
r.inset(0, 20);
|
||||
paint.setXfermode(mode);
|
||||
canvas->drawOval(r, paint);
|
||||
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
class LerpXfermodeGM : public skiagm::GM {
|
||||
public:
|
||||
LerpXfermodeGM() {}
|
||||
|
||||
protected:
|
||||
virtual SkString onShortName() SK_OVERRIDE {
|
||||
return SkString("lerpmode");
|
||||
}
|
||||
|
||||
virtual SkISize onISize() SK_OVERRIDE {
|
||||
return SkISize::Make(240, 120);
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
|
||||
show_circlelayers(canvas, NULL);
|
||||
canvas->translate(150, 0);
|
||||
SkAutoTUnref<SkXfermode> mode(SkLerpXfermode::Create(0.5f));
|
||||
show_circlelayers(canvas, mode.get());
|
||||
}
|
||||
|
||||
private:
|
||||
typedef skiagm::GM INHERITED;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEF_GM( return SkNEW(LerpXfermodeGM); )
|
||||
|
@ -34,6 +34,7 @@
|
||||
'<(skia_src_path)/effects/SkKernel33MaskFilter.cpp',
|
||||
'<(skia_src_path)/effects/SkLayerDrawLooper.cpp',
|
||||
'<(skia_src_path)/effects/SkLayerRasterizer.cpp',
|
||||
'<(skia_src_path)/effects/SkLerpXfermode.cpp',
|
||||
'<(skia_src_path)/effects/SkLightingImageFilter.cpp',
|
||||
'<(skia_src_path)/effects/SkMatrixConvolutionImageFilter.cpp',
|
||||
'<(skia_src_path)/effects/SkMergeImageFilter.cpp',
|
||||
@ -91,6 +92,7 @@
|
||||
'<(skia_include_path)/effects/SkKernel33MaskFilter.h',
|
||||
'<(skia_include_path)/effects/SkLayerDrawLooper.h',
|
||||
'<(skia_include_path)/effects/SkLayerRasterizer.h',
|
||||
'<(skia_include_path)/effects/SkLerpXfermode.h',
|
||||
'<(skia_include_path)/effects/SkLightingImageFilter.h',
|
||||
'<(skia_include_path)/effects/SkOffsetImageFilter.h',
|
||||
'<(skia_include_path)/effects/SkMorphologyImageFilter.h',
|
||||
|
@ -49,6 +49,7 @@
|
||||
'../gm/hittestpath.cpp',
|
||||
'../gm/imageblur.cpp',
|
||||
'../gm/imagemagnifier.cpp',
|
||||
'../gm/lerpmode.cpp',
|
||||
'../gm/lighting.cpp',
|
||||
'../src/image/SkImage_Codec.cpp',
|
||||
'../gm/image.cpp',
|
||||
|
@ -273,16 +273,16 @@ static inline SkPMColor SkFourByteInterp(SkPMColor src, SkPMColor dst,
|
||||
* architectures than an equivalent 64b version and 30% faster than
|
||||
* SkFourByteInterp(). Third parameter controls blending of the first two:
|
||||
* (src, dst, 0) returns dst
|
||||
* (src, dst, 0xFF) returns src
|
||||
* ** Does not match the results of SkFourByteInterp() because we use
|
||||
* (src, dst, 256) returns src
|
||||
* ** Does not match the results of SkFourByteInterp256() because we use
|
||||
* a more accurate scale computation!
|
||||
* TODO: migrate Skia function to using an accurate 255->266 alpha
|
||||
* conversion.
|
||||
*/
|
||||
static inline SkPMColor SkFastFourByteInterp(SkPMColor src,
|
||||
SkPMColor dst,
|
||||
U8CPU srcWeight) {
|
||||
SkASSERT(srcWeight < 256);
|
||||
static inline SkPMColor SkFastFourByteInterp256(SkPMColor src,
|
||||
SkPMColor dst,
|
||||
unsigned scale) {
|
||||
SkASSERT(scale <= 256);
|
||||
|
||||
// Reorders ARGB to AG-RB in order to reduce the number of operations.
|
||||
const uint32_t mask = 0xFF00FF;
|
||||
@ -291,16 +291,21 @@ static inline SkPMColor SkFastFourByteInterp(SkPMColor src,
|
||||
uint32_t dst_rb = dst & mask;
|
||||
uint32_t dst_ag = (dst >> 8) & mask;
|
||||
|
||||
// scale = srcWeight + (srcWeight >> 7) is more accurate than
|
||||
// scale = srcWeight + 1, but 7% slower
|
||||
int scale = srcWeight + (srcWeight >> 7);
|
||||
|
||||
uint32_t ret_rb = src_rb * scale + (256 - scale) * dst_rb;
|
||||
uint32_t ret_ag = src_ag * scale + (256 - scale) * dst_ag;
|
||||
|
||||
return (ret_ag & ~mask) | ((ret_rb & ~mask) >> 8);
|
||||
}
|
||||
|
||||
static inline SkPMColor SkFastFourByteInterp(SkPMColor src,
|
||||
SkPMColor dst,
|
||||
U8CPU srcWeight) {
|
||||
SkASSERT(srcWeight <= 255);
|
||||
// scale = srcWeight + (srcWeight >> 7) is more accurate than
|
||||
// scale = srcWeight + 1, but 7% slower
|
||||
return SkFastFourByteInterp256(src, dst, srcWeight + (srcWeight >> 7));
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as SkPackARGB32, but this version guarantees to not check that the
|
||||
* values are premultiplied in the debug version.
|
||||
|
46
include/effects/SkLerpXfermode.h
Normal file
46
include/effects/SkLerpXfermode.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkLerpXfermode_DEFINED
|
||||
#define SkLerpXfermode_DEFINED
|
||||
|
||||
#include "SkXfermode.h"
|
||||
|
||||
class SK_API SkLerpXfermode : public SkXfermode {
|
||||
public:
|
||||
/**
|
||||
* result = scale * src + (1 - scale) * dst
|
||||
*
|
||||
* When scale == 1, this is the same as kSrc_Mode
|
||||
* When scale == 0, this is the same as kDst_Mode
|
||||
*/
|
||||
static SkXfermode* Create(SkScalar scale);
|
||||
|
||||
// overrides from SkXfermode
|
||||
virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
|
||||
const SkAlpha aa[]) const SK_OVERRIDE;
|
||||
virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count,
|
||||
const SkAlpha aa[]) const SK_OVERRIDE;
|
||||
virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
|
||||
const SkAlpha aa[]) const SK_OVERRIDE;
|
||||
|
||||
SK_DEVELOPER_TO_STRING()
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLerpXfermode)
|
||||
|
||||
protected:
|
||||
SkLerpXfermode(SkFlattenableReadBuffer&);
|
||||
virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkLerpXfermode(unsigned scale256);
|
||||
|
||||
unsigned fScale256; // 0..256
|
||||
|
||||
typedef SkXfermode INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
110
src/effects/SkLerpXfermode.cpp
Normal file
110
src/effects/SkLerpXfermode.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkLerpXfermode.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
#include "SkString.h"
|
||||
|
||||
SkXfermode* SkLerpXfermode::Create(SkScalar scale) {
|
||||
int scale256 = SkScalarRoundToInt(scale * 256);
|
||||
if (scale256 >= 256) {
|
||||
return SkXfermode::Create(SkXfermode::kSrc_Mode);
|
||||
} else if (scale256 <= 0) {
|
||||
return SkXfermode::Create(SkXfermode::kDst_Mode);
|
||||
}
|
||||
return SkNEW_ARGS(SkLerpXfermode, (scale256));
|
||||
}
|
||||
|
||||
SkLerpXfermode::SkLerpXfermode(unsigned scale256) : fScale256(scale256) {}
|
||||
|
||||
SkLerpXfermode::SkLerpXfermode(SkFlattenableReadBuffer& buffer)
|
||||
: INHERITED(buffer) {
|
||||
fScale256 = buffer.readUInt();
|
||||
}
|
||||
|
||||
void SkLerpXfermode::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
this->INHERITED::flatten(buffer);
|
||||
buffer.writeUInt(fScale256);
|
||||
}
|
||||
|
||||
void SkLerpXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
|
||||
const SkAlpha aa[]) const {
|
||||
const int scale = fScale256;
|
||||
|
||||
if (aa) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
unsigned a = aa[i];
|
||||
if (a) {
|
||||
SkPMColor dstC = dst[i];
|
||||
SkPMColor resC = SkFastFourByteInterp256(src[i], dstC, scale);
|
||||
if (a < 255) {
|
||||
resC = SkFastFourByteInterp256(resC, dstC, a + (a >> 7));
|
||||
}
|
||||
dst[i] = resC;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
dst[i] = SkFastFourByteInterp256(src[i], dst[i], scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkLerpXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
|
||||
const SkAlpha aa[]) const {
|
||||
const int scale = fScale256;
|
||||
|
||||
if (aa) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
unsigned a = aa[i];
|
||||
if (a) {
|
||||
SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
|
||||
SkPMColor resC = SkFastFourByteInterp256(src[i], dstC, scale);
|
||||
if (a < 255) {
|
||||
resC = SkFastFourByteInterp256(resC, dstC, a + (a >> 7));
|
||||
}
|
||||
dst[i] = SkPixel32ToPixel16(resC);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
|
||||
SkPMColor resC = SkFastFourByteInterp256(src[i], dstC, scale);
|
||||
dst[i] = SkPixel32ToPixel16(resC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkLerpXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count,
|
||||
const SkAlpha aa[]) const {
|
||||
const int scale = fScale256;
|
||||
|
||||
if (aa) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
unsigned a = aa[i];
|
||||
if (a) {
|
||||
unsigned dstA = dst[i];
|
||||
unsigned resA = SkAlphaBlend(SkGetPackedA32(src[i]), dstA, scale);
|
||||
if (a < 255) {
|
||||
resA = SkAlphaBlend(resA, dstA, a + (a >> 7));
|
||||
}
|
||||
dst[i] = resA;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
dst[i] = SkAlphaBlend(SkGetPackedA32(src[i]), dst[i], scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SK_DEVELOPER
|
||||
void SkLerpXfermode::toString(SkString* str) const {
|
||||
str->printf("SkLerpXfermode: scale: %g", fScale256 / 256.0);
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user