Index: src/core/SkLightingShader.cpp |
diff --git a/src/core/SkLightingShader.cpp b/src/core/SkLightingShader.cpp |
index 52b208f8df6f2ff848513f8ea1cedc246c7c7bea..ca1c3417b4581ab5c404654e6acc4bd51bd8858c 100644 |
--- a/src/core/SkLightingShader.cpp |
+++ b/src/core/SkLightingShader.cpp |
@@ -12,7 +12,6 @@ |
#include "SkErrorInternals.h" |
#include "SkLightingShader.h" |
#include "SkMathPriv.h" |
-#include "SkNormalSource.h" |
#include "SkPoint3.h" |
#include "SkReadBuffer.h" |
#include "SkWriteBuffer.h" |
@@ -56,7 +55,7 @@ |
const sk_sp<SkLights> lights, |
const SkVector& invNormRotation, |
const SkMatrix* diffLocalM, const SkMatrix* normLocalM, |
- sk_sp<SkNormalSource> normalSource) |
+ sk_sp<SkLightingShader::NormalSource> normalSource) |
: INHERITED(diffLocalM) |
, fDiffuseMap(diffuse) |
, fNormalMap(normal) |
@@ -89,7 +88,7 @@ |
// The context takes ownership of the states. It will call their destructors |
// but will NOT free the memory. |
LightingShaderContext(const SkLightingShaderImpl&, const ContextRec&, |
- SkBitmapProcState* diffuseState, SkNormalSource::Provider*); |
+ SkBitmapProcState* diffuseState, SkBitmapProcState* normalState); |
~LightingShaderContext() override; |
void shadeSpan(int x, int y, SkPMColor[], int count) override; |
@@ -97,9 +96,9 @@ |
uint32_t getFlags() const override { return fFlags; } |
private: |
- SkBitmapProcState* fDiffuseState; |
- SkNormalSource::Provider* fNormalProvider; |
- uint32_t fFlags; |
+ SkBitmapProcState* fDiffuseState; |
+ SkBitmapProcState* fNormalState; |
+ uint32_t fFlags; |
typedef SkShader::Context INHERITED; |
}; |
@@ -111,6 +110,7 @@ |
void flatten(SkWriteBuffer&) const override; |
size_t onContextSize(const ContextRec&) const override; |
Context* onCreateContext(const ContextRec&, void*) const override; |
+ bool computeNormTotalInverse(const ContextRec& rec, SkMatrix* normTotalInverse) const; |
private: |
SkBitmap fDiffuseMap; |
@@ -121,7 +121,7 @@ |
SkMatrix fNormLocalMatrix; |
SkVector fInvNormRotation; |
- sk_sp<SkNormalSource> fNormalSource; |
+ sk_sp<SkLightingShader::NormalSource> fNormalSource; |
friend class SkLightingShader; |
@@ -367,11 +367,13 @@ |
} |
SkLightingShaderImpl::LightingShaderContext::LightingShaderContext( |
- const SkLightingShaderImpl& shader, const ContextRec& rec, SkBitmapProcState* diffuseState, |
- SkNormalSource::Provider* normalProvider) |
+ const SkLightingShaderImpl& shader, |
+ const ContextRec& rec, |
+ SkBitmapProcState* diffuseState, |
+ SkBitmapProcState* normalState) |
: INHERITED(shader, rec) |
, fDiffuseState(diffuseState) |
- , fNormalProvider(normalProvider) { |
+ , fNormalState(normalState) { |
const SkPixmap& pixmap = fDiffuseState->fPixmap; |
bool isOpaque = pixmap.isOpaque(); |
@@ -388,7 +390,7 @@ |
// The bitmap proc states have been created outside of the context on memory that will be freed |
// elsewhere. Call the destructors but leave the freeing of the memory to the caller. |
fDiffuseState->~SkBitmapProcState(); |
- fNormalProvider->~Provider(); |
+ fNormalState->~SkBitmapProcState(); |
} |
static inline SkPMColor convert(SkColor3f color, U8CPU a) { |
@@ -415,24 +417,29 @@ |
// larger is better (fewer times we have to loop), but we shouldn't |
// take up too much stack-space (each one here costs 16 bytes) |
-#define TMP_COUNT 16 |
-#define BUFFER_MAX ((int)(TMP_COUNT * sizeof(uint32_t))) |
+#define TMP_COUNT 16 |
+ |
void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y, |
SkPMColor result[], int count) { |
const SkLightingShaderImpl& lightShader = static_cast<const SkLightingShaderImpl&>(fShader); |
- uint32_t tmpColor[TMP_COUNT]; |
- SkPMColor tmpColor2[2*TMP_COUNT]; |
+ uint32_t tmpColor[TMP_COUNT], tmpNormal[TMP_COUNT]; |
+ SkPMColor tmpColor2[2*TMP_COUNT], tmpNormal2[2*TMP_COUNT]; |
SkBitmapProcState::MatrixProc diffMProc = fDiffuseState->getMatrixProc(); |
SkBitmapProcState::SampleProc32 diffSProc = fDiffuseState->getSampleProc32(); |
- int max = fDiffuseState->maxCountForBufferSize(BUFFER_MAX); |
+ SkBitmapProcState::MatrixProc normalMProc = fNormalState->getMatrixProc(); |
+ SkBitmapProcState::SampleProc32 normalSProc = fNormalState->getSampleProc32(); |
+ |
+ int diffMax = fDiffuseState->maxCountForBufferSize(sizeof(tmpColor[0]) * TMP_COUNT); |
+ int normMax = fNormalState->maxCountForBufferSize(sizeof(tmpNormal[0]) * TMP_COUNT); |
+ int max = SkTMin(diffMax, normMax); |
SkASSERT(fDiffuseState->fPixmap.addr()); |
- |
- SkASSERT(max <= BUFFER_MAX); |
- SkPoint3 normals[BUFFER_MAX]; |
+ SkASSERT(fNormalState->fPixmap.addr()); |
+ |
+ SkPoint3 norm, xformedNorm; |
do { |
int n = count; |
@@ -443,9 +450,21 @@ |
diffMProc(*fDiffuseState, tmpColor, n, x, y); |
diffSProc(*fDiffuseState, tmpColor, n, tmpColor2); |
- fNormalProvider->fillScanLine(x, y, normals, n); |
+ normalMProc(*fNormalState, tmpNormal, n, x, y); |
+ normalSProc(*fNormalState, tmpNormal, n, tmpNormal2); |
for (int i = 0; i < n; ++i) { |
+ SkASSERT(0xFF == SkColorGetA(tmpNormal2[i])); // opaque -> unpremul |
+ norm.set(SkIntToScalar(SkGetPackedR32(tmpNormal2[i]))-127.0f, |
+ SkIntToScalar(SkGetPackedG32(tmpNormal2[i]))-127.0f, |
+ SkIntToScalar(SkGetPackedB32(tmpNormal2[i]))-127.0f); |
+ norm.normalize(); |
+ |
+ xformedNorm.fX = lightShader.fInvNormRotation.fX * norm.fX + |
+ lightShader.fInvNormRotation.fY * norm.fY; |
+ xformedNorm.fY = -lightShader.fInvNormRotation.fY * norm.fX + |
+ lightShader.fInvNormRotation.fX * norm.fY; |
+ xformedNorm.fZ = norm.fZ; |
SkColor diffColor = SkUnPreMultiply::PMColorToColor(tmpColor2[i]); |
@@ -457,7 +476,7 @@ |
if (SkLights::Light::kAmbient_LightType == light.type()) { |
accum += light.color().makeScale(255.0f); |
} else { |
- SkScalar NdotL = normals[i].dot(light.dir()); |
+ SkScalar NdotL = xformedNorm.dot(light.dir()); |
if (NdotL < 0.0f) { |
NdotL = 0.0f; |
} |
@@ -544,7 +563,8 @@ |
invNormRotation = buf.readPoint(); |
} |
- sk_sp<SkNormalSource> normalSource(buf.readFlattenable<SkNormalSource>()); |
+ sk_sp<SkLightingShader::NormalSource> normalSource( |
+ buf.readFlattenable<SkLightingShader::NormalSource>()); |
return sk_make_sp<SkLightingShaderImpl>(diffuse, normal, std::move(lights), invNormRotation, |
&diffLocalM, &normLocalM, std::move(normalSource)); |
@@ -579,10 +599,21 @@ |
buf.writeFlattenable(fNormalSource.get()); |
} |
-size_t SkLightingShaderImpl::onContextSize(const ContextRec& rec) const { |
- return sizeof(LightingShaderContext) + |
- sizeof(SkBitmapProcState) + |
- fNormalSource->providerSize(rec); |
+bool SkLightingShaderImpl::computeNormTotalInverse(const ContextRec& rec, |
+ SkMatrix* normTotalInverse) const { |
+ SkMatrix total; |
+ total.setConcat(*rec.fMatrix, fNormLocalMatrix); |
+ |
+ const SkMatrix* m = &total; |
+ if (rec.fLocalMatrix) { |
+ total.setConcat(*m, *rec.fLocalMatrix); |
+ m = &total; |
+ } |
+ return m->invert(normTotalInverse); |
+} |
+ |
+size_t SkLightingShaderImpl::onContextSize(const ContextRec&) const { |
+ return 2 * sizeof(SkBitmapProcState) + sizeof(LightingShaderContext); |
} |
SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec, |
@@ -591,6 +622,11 @@ |
SkMatrix diffTotalInv; |
// computeTotalInverse was called in SkShader::createContext so we know it will succeed |
SkAssertResult(this->computeTotalInverse(rec, &diffTotalInv)); |
+ |
+ SkMatrix normTotalInv; |
+ if (!this->computeNormTotalInverse(rec, &normTotalInv)) { |
+ return nullptr; |
+ } |
void* diffuseStateStorage = (char*)storage + sizeof(LightingShaderContext); |
SkBitmapProcState* diffuseState = new (diffuseStateStorage) SkBitmapProcState(fDiffuseMap, |
@@ -601,18 +637,21 @@ |
diffuseState->~SkBitmapProcState(); |
return nullptr; |
} |
- void* normalProviderStorage = (char*)storage + |
- sizeof(LightingShaderContext) + |
- sizeof(SkBitmapProcState); |
- |
- SkNormalSource::Provider* normalProvider = fNormalSource->asProvider(rec, |
- normalProviderStorage); |
- if (!normalProvider) { |
+ |
+ void* normalStateStorage = (char*)storage + |
+ sizeof(LightingShaderContext) + |
+ sizeof(SkBitmapProcState); |
+ SkBitmapProcState* normalState = new (normalStateStorage) SkBitmapProcState(fNormalMap, |
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, |
+ SkMipMap::DeduceTreatment(rec)); |
+ SkASSERT(normalState); |
+ if (!normalState->setup(normTotalInv, *rec.fPaint)) { |
diffuseState->~SkBitmapProcState(); |
- return nullptr; |
- } |
- |
- return new (storage) LightingShaderContext(*this, rec, diffuseState, normalProvider); |
+ normalState->~SkBitmapProcState(); |
+ return nullptr; |
+ } |
+ |
+ return new (storage) LightingShaderContext(*this, rec, diffuseState, normalState); |
} |
/////////////////////////////////////////////////////////////////////////////// |
@@ -629,12 +668,8 @@ |
} |
SkASSERT(SkScalarNearlyEqual(invNormRotation.lengthSqd(), SK_Scalar1)); |
- // TODO: support other tile modes |
- sk_sp<SkShader> mapShader = SkMakeBitmapShader(normal, SkShader::kClamp_TileMode, |
- SkShader::kClamp_TileMode, normLocalM, nullptr); |
- |
- sk_sp<SkNormalSource> normalSource = SkNormalSource::MakeFromNormalMap(mapShader, |
- invNormRotation); |
+ sk_sp<SkLightingShader::NormalSource> normalSource = |
+ SkLightingShader::NormalSource::MakeMap(normal, invNormRotation, normLocalM); |
return sk_make_sp<SkLightingShaderImpl>(diffuse, normal, std::move(lights), |
invNormRotation, diffLocalM, normLocalM, std::move(normalSource)); |