Index: src/core/SkNormalSource.cpp |
diff --git a/src/core/SkLightingShader_NormalSource.cpp b/src/core/SkNormalSource.cpp |
similarity index 54% |
rename from src/core/SkLightingShader_NormalSource.cpp |
rename to src/core/SkNormalSource.cpp |
index b96b1bf083c314b4f6e33f94bb21b5c0c5c0fb59..cadf47e29ce5b57dfa96acf13136541a6515d4dd 100644 |
--- a/src/core/SkLightingShader_NormalSource.cpp |
+++ b/src/core/SkNormalSource.cpp |
@@ -6,32 +6,24 @@ |
*/ |
#include "SkBitmapProcShader.h" |
+#include "SkBitmapProcState.h" |
#include "SkError.h" |
#include "SkErrorInternals.h" |
#include "SkLightingShader.h" |
+#include "SkNormalSource.h" |
#include "SkReadBuffer.h" |
#include "SkWriteBuffer.h" |
// Genretating vtable |
-SkLightingShader::NormalSource::~NormalSource() {} |
+SkNormalSource::~SkNormalSource() {} |
/////////////////////////////////////////////////////////////////////////////// |
-class NormalMapSourceImpl : public SkLightingShader::NormalSource { |
+class NormalMapSourceImpl : public SkNormalSource { |
public: |
- NormalMapSourceImpl(const SkBitmap &normal, const SkVector &invNormRotation, |
- const SkMatrix *normLocalM) |
- : fNormalMap(normal) |
- , fInvNormRotation(invNormRotation) { |
- |
- if (normLocalM) { |
- fNormLocalMatrix = *normLocalM; |
- } else { |
- fNormLocalMatrix.reset(); |
- } |
- // Pre-cache so future calls to fNormLocalMatrix.getType() are threadsafe. |
- (void)fNormLocalMatrix.getType(); |
- } |
+ NormalMapSourceImpl(sk_sp<SkShader> bitmapShader, const SkVector &invNormRotation) |
+ : fBitmapShader(std::move(bitmapShader)) |
+ , fInvNormRotation(invNormRotation) {} |
#if SK_SUPPORT_GPU |
sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*, |
@@ -41,19 +33,38 @@ public: |
SkSourceGammaTreatment) const override; |
#endif |
+ SkNormalSource::Provider* asProvider(const SkShader::ContextRec& rec, |
+ void* storage) const override; |
+ |
+ size_t providerSize(const SkShader::ContextRec& rec) const override; |
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(NormalMapSourceImpl) |
protected: |
void flatten(SkWriteBuffer& buf) const override; |
+ bool computeNormTotalInverse(const SkShader::ContextRec& rec, SkMatrix* normTotalInverse) const; |
+ |
private: |
- SkBitmap fNormalMap; |
- SkMatrix fNormLocalMatrix; |
+ class Provider : public SkNormalSource::Provider { |
+ public: |
+ Provider(const NormalMapSourceImpl& source, SkShader::Context* fBitmapContext); |
+ |
+ virtual ~Provider(); |
+ |
+ void fillScanLine(int x, int y, SkPoint3 output[], int count) const override; |
+ private: |
+ const NormalMapSourceImpl& fSource; |
+ SkShader::Context* fBitmapContext; |
+ |
+ typedef SkNormalSource::Provider INHERITED; |
+ }; |
+ |
+ sk_sp<SkShader> fBitmapShader; |
SkVector fInvNormRotation; |
- friend class SkLightingShader::NormalSource; |
+ friend class SkNormalSource; |
- typedef SkLightingShader::NormalSource INHERITED; |
+ typedef SkNormalSource INHERITED; |
}; |
//////////////////////////////////////////////////////////////////////////// |
@@ -69,13 +80,9 @@ private: |
class NormalMapFP : public GrFragmentProcessor { |
public: |
- NormalMapFP(GrTexture* normal, const SkMatrix& normMatrix, const GrTextureParams& normParams, |
- const SkVector& invNormRotation) |
- : fNormDeviceTransform(kLocal_GrCoordSet, normMatrix, normal, normParams.filterMode()) |
- , fNormalTextureAccess(normal, normParams) |
- , fInvNormRotation(invNormRotation) { |
- this->addCoordTransform(&fNormDeviceTransform); |
- this->addTextureAccess(&fNormalTextureAccess); |
+ NormalMapFP(sk_sp<GrFragmentProcessor> bitmapFP, const SkVector& invNormRotation) |
+ : fInvNormRotation(invNormRotation) { |
+ this->registerChildProcessor(bitmapFP); |
this->initClassID<NormalMapFP>(); |
} |
@@ -97,13 +104,10 @@ public: |
kVec2f_GrSLType, kDefault_GrSLPrecision, |
"Xform", &xformUniName); |
- fragBuilder->codeAppend("vec4 normalColor = "); |
- fragBuilder->appendTextureLookup(args.fTexSamplers[0], |
- args.fCoords[0].c_str(), |
- args.fCoords[0].getType()); |
- fragBuilder->codeAppend(";"); |
- |
- fragBuilder->codeAppend("vec3 normal = normalColor.rgb - vec3(0.5);"); |
+ SkString dstNormalColorName("dstNormalColor"); |
+ this->emitChild(0, nullptr, &dstNormalColorName, args); |
+ fragBuilder->codeAppendf("vec3 normal = %s.rgb - vec3(0.5);", |
+ dstNormalColorName.c_str()); |
// TODO: inverse map the light direction vectors in the vertex shader rather than |
// transforming all the normals here! |
@@ -153,40 +157,12 @@ private: |
bool onIsEqual(const GrFragmentProcessor& proc) const override { |
const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>(); |
- return fNormDeviceTransform == normalMapFP.fNormDeviceTransform && |
- fNormalTextureAccess == normalMapFP.fNormalTextureAccess && |
- fInvNormRotation == normalMapFP.fInvNormRotation; |
+ return fInvNormRotation == normalMapFP.fInvNormRotation; |
} |
- GrCoordTransform fNormDeviceTransform; |
- GrTextureAccess fNormalTextureAccess; |
- SkVector fInvNormRotation; |
+ SkVector fInvNormRotation; |
}; |
-// TODO same code at SkLightingShader.cpp. Refactor to common source! |
-static bool make_mat(const SkBitmap& bm, |
- const SkMatrix& localMatrix1, |
- const SkMatrix* localMatrix2, |
- SkMatrix* result) { |
- |
- result->setIDiv(bm.width(), bm.height()); |
- |
- SkMatrix lmInverse; |
- if (!localMatrix1.invert(&lmInverse)) { |
- return false; |
- } |
- if (localMatrix2) { |
- SkMatrix inv; |
- if (!localMatrix2->invert(&inv)) { |
- return false; |
- } |
- lmInverse.postConcat(inv); |
- } |
- result->preConcat(lmInverse); |
- |
- return true; |
-} |
- |
sk_sp<GrFragmentProcessor> NormalMapSourceImpl::asFragmentProcessor( |
GrContext *context, |
const SkMatrix &viewM, |
@@ -194,96 +170,132 @@ sk_sp<GrFragmentProcessor> NormalMapSourceImpl::asFragmentProcessor( |
SkFilterQuality filterQuality, |
SkSourceGammaTreatment gammaTreatment) const { |
- // TODO Here, the old code was checking that diffuse map and normal map are same size, that |
- // will be addressed when diffuse maps are factored out of SkLightingShader in a future CL |
+ sk_sp<GrFragmentProcessor> bitmapFP = fBitmapShader->asFragmentProcessor(context, viewM, |
+ localMatrix, filterQuality, gammaTreatment); |
+ |
+ return sk_make_sp<NormalMapFP>(std::move(bitmapFP), fInvNormRotation); |
+} |
+ |
+#endif // SK_SUPPORT_GPU |
+ |
+//////////////////////////////////////////////////////////////////////////// |
+ |
+NormalMapSourceImpl::Provider::Provider(const NormalMapSourceImpl& source, |
+ SkShader::Context* bitmapContext) |
+ : fSource(source) |
+ , fBitmapContext(bitmapContext) { |
+} |
+ |
+NormalMapSourceImpl::Provider::~Provider() { |
+ fBitmapContext->~Context(); |
+} |
- SkMatrix normM; |
- if (!make_mat(fNormalMap, fNormLocalMatrix, localMatrix, &normM)) { |
+SkNormalSource::Provider* NormalMapSourceImpl::asProvider( |
+ const SkShader::ContextRec &rec, void *storage) const { |
+ SkMatrix normTotalInv; |
+ if (!this->computeNormTotalInverse(rec, &normTotalInv)) { |
return nullptr; |
} |
- bool doBicubic; |
- GrTextureParams::FilterMode normFilterMode = GrSkFilterQualityToGrFilterMode( |
- SkTMin(filterQuality, kMedium_SkFilterQuality), |
- viewM, |
- fNormLocalMatrix, |
- &doBicubic); |
- SkASSERT(!doBicubic); |
- |
- // TODO: support other tile modes |
- GrTextureParams normParams(SkShader::kClamp_TileMode, normFilterMode); |
- SkAutoTUnref<GrTexture> normalTexture(GrRefCachedBitmapTexture(context, |
- fNormalMap, |
- normParams, |
- gammaTreatment)); |
- if (!normalTexture) { |
- SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture."); |
+ void* bitmapContextStorage = (char*)storage + sizeof(Provider); |
+ SkShader::Context* context = fBitmapShader->createContext(rec, bitmapContextStorage); |
+ if (!context) { |
return nullptr; |
} |
- return sk_make_sp<NormalMapFP>(normalTexture, normM, normParams, fInvNormRotation); |
+ return new (storage) Provider(*this, context); |
} |
-#endif // SK_SUPPORT_GPU |
- |
-//////////////////////////////////////////////////////////////////////////// |
+size_t NormalMapSourceImpl::providerSize(const SkShader::ContextRec& rec) const { |
+ return sizeof(Provider) + fBitmapShader->contextSize(rec); |
+} |
-sk_sp<SkFlattenable> NormalMapSourceImpl::CreateProc(SkReadBuffer& buf) { |
+bool NormalMapSourceImpl::computeNormTotalInverse(const SkShader::ContextRec& rec, |
+ SkMatrix* normTotalInverse) const { |
+ SkMatrix total; |
+ total.setConcat(*rec.fMatrix, fBitmapShader->getLocalMatrix()); |
- SkMatrix normLocalM; |
- bool hasNormLocalM = buf.readBool(); |
- if (hasNormLocalM) { |
- buf.readMatrix(&normLocalM); |
- } else { |
- normLocalM.reset(); |
+ const SkMatrix* m = &total; |
+ if (rec.fLocalMatrix) { |
+ total.setConcat(*m, *rec.fLocalMatrix); |
+ m = &total; |
} |
+ return m->invert(normTotalInverse); |
+} |
- SkBitmap normal; |
- if (!buf.readBitmap(&normal)) { |
- return nullptr; |
- } |
- normal.setImmutable(); |
+#define BUFFER_MAX 16 |
+void NormalMapSourceImpl::Provider::fillScanLine(int x, int y, SkPoint3 output[], |
+ int count) const { |
+ SkPMColor tmpNormalColors[BUFFER_MAX]; |
+ |
+ do { |
+ int n = SkTMin(count, BUFFER_MAX); |
+ |
+ fBitmapContext->shadeSpan(x, y, tmpNormalColors, n); |
+ |
+ for (int i = 0; i < n; i++) { |
+ SkPoint3 tempNorm; |
+ |
+ tempNorm.set(SkIntToScalar(SkGetPackedR32(tmpNormalColors[i])) - 127.0f, |
+ SkIntToScalar(SkGetPackedG32(tmpNormalColors[i])) - 127.0f, |
+ SkIntToScalar(SkGetPackedB32(tmpNormalColors[i])) - 127.0f); |
+ tempNorm.normalize(); |
+ |
+ output[i].fX = fSource.fInvNormRotation.fX * tempNorm.fX + |
+ fSource.fInvNormRotation.fY * tempNorm.fY; |
+ output[i].fY = -fSource.fInvNormRotation.fY * tempNorm.fX + |
+ fSource.fInvNormRotation.fX * tempNorm.fY; |
+ output[i].fZ = tempNorm.fZ; |
+ } |
+ |
+ output += n; |
+ x += n; |
+ count -= n; |
+ } while (count > 0); |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+ |
+sk_sp<SkFlattenable> NormalMapSourceImpl::CreateProc(SkReadBuffer& buf) { |
+ |
+ sk_sp<SkShader> bitmapShader = buf.readFlattenable<SkShader>(); |
SkVector invNormRotation = {1,0}; |
if (!buf.isVersionLT(SkReadBuffer::kLightingShaderWritesInvNormRotation)) { |
invNormRotation = buf.readPoint(); |
} |
- return sk_make_sp<NormalMapSourceImpl>(normal, invNormRotation, &normLocalM); |
+ return sk_make_sp<NormalMapSourceImpl>(std::move(bitmapShader), invNormRotation); |
} |
void NormalMapSourceImpl::flatten(SkWriteBuffer& buf) const { |
this->INHERITED::flatten(buf); |
- bool hasNormLocalM = !fNormLocalMatrix.isIdentity(); |
- buf.writeBool(hasNormLocalM); |
- if (hasNormLocalM) { |
- buf.writeMatrix(fNormLocalMatrix); |
- } |
- |
- buf.writeBitmap(fNormalMap); |
+ buf.writeFlattenable(fBitmapShader.get()); |
buf.writePoint(fInvNormRotation); |
} |
//////////////////////////////////////////////////////////////////////////// |
-sk_sp<SkLightingShader::NormalSource> SkLightingShader::NormalSource::MakeMap( |
+sk_sp<SkNormalSource> SkNormalSource::MakeMap( |
const SkBitmap &normal, const SkVector &invNormRotation, const SkMatrix *normLocalM) { |
- // TODO not checking normal and diffuse maps to be same size, will be addressed when diffuse |
- // maps are factored out of SkLightingShader in a future CL |
if (normal.isNull() || SkBitmapProcShader::BitmapIsTooBig(normal)) { |
return nullptr; |
} |
SkASSERT(SkScalarNearlyEqual(invNormRotation.lengthSqd(), SK_Scalar1)); |
- return sk_make_sp<NormalMapSourceImpl>(normal, invNormRotation, normLocalM); |
+ // TODO: support other tile modes |
+ sk_sp<SkShader> bitmapShader = SkMakeBitmapShader(normal, SkShader::kClamp_TileMode, |
+ SkShader::kClamp_TileMode, normLocalM, nullptr); |
+ |
+ return sk_make_sp<NormalMapSourceImpl>(std::move(bitmapShader), invNormRotation); |
} |
//////////////////////////////////////////////////////////////////////////// |
-SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingShader::NormalSource) |
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkNormalSource) |
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(NormalMapSourceImpl) |
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |