'<(skia_src_path)/core/SkLayerInfo.h',
'<(skia_src_path)/core/SkLightingShader.h',
'<(skia_src_path)/core/SkLightingShader.cpp',
+ '<(skia_src_path)/core/SkLightingShader_NormalSource.cpp',
'<(skia_src_path)/core/SkLinearBitmapPipeline.cpp',
'<(skia_src_path)/core/SkLinearBitmapPipeline.h',
'<(skia_src_path)/core/SkLinearBitmapPipeline_core.h',
'<(skia_src_path)/core/SkNextID.h',
'<(skia_src_path)/core/SkNinePatchIter.cpp',
'<(skia_src_path)/core/SkNinePatchIter.h',
- '<(skia_src_path)/core/SkNormalSource.cpp',
- '<(skia_src_path)/core/SkNormalSource.h',
'<(skia_src_path)/core/SkNx.h',
'<(skia_src_path)/core/SkOpts.cpp',
'<(skia_src_path)/core/SkOpts.h',
kSkShader_Type,
kSkUnused_Type, // used to be SkUnitMapper
kSkXfermode_Type,
- kSkNormalSource_Type,
+ kNormalSource_Type,
};
typedef sk_sp<SkFlattenable> (*Factory)(SkReadBuffer&);
#include "SkErrorInternals.h"
#include "SkLightingShader.h"
#include "SkMathPriv.h"
-#include "SkNormalSource.h"
#include "SkPoint3.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"
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)
// 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;
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;
};
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;
SkMatrix fNormLocalMatrix;
SkVector fInvNormRotation;
- sk_sp<SkNormalSource> fNormalSource;
+ sk_sp<SkLightingShader::NormalSource> fNormalSource;
friend class SkLightingShader;
}
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();
// 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) {
// 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(fNormalState->fPixmap.addr());
- SkASSERT(max <= BUFFER_MAX);
- SkPoint3 normals[BUFFER_MAX];
+ SkPoint3 norm, xformedNorm;
do {
int n = count;
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]);
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;
}
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));
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,
// 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,
SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
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();
+ normalState->~SkBitmapProcState();
return nullptr;
}
- return new (storage) LightingShaderContext(*this, rec, diffuseState, normalProvider);
+ return new (storage) LightingShaderContext(*this, rec, diffuseState, normalState);
}
///////////////////////////////////////////////////////////////////////////////
}
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));
class SK_API SkLightingShader {
public:
+ /** Abstract class that generates or reads in normals for use by SkLightingShader. Currently
+ implements the GPU side only. Not to be used as part of the API yet. Used internally by
+ SkLightingShader.
+ */
+ class SK_API NormalSource : public SkFlattenable {
+ public:
+ virtual ~NormalSource();
+
+#if SK_SUPPORT_GPU
+ /** Returns a fragment processor that takes no input and outputs a normal (already rotated)
+ as its output color. To be used as a child fragment processor.
+ */
+ virtual sk_sp<GrFragmentProcessor> asFragmentProcessor(
+ GrContext* context,
+ const SkMatrix& viewM,
+ const SkMatrix* localMatrix,
+ SkFilterQuality filterQuality,
+ SkSourceGammaTreatment gammaTreatment) const = 0;
+#endif
+
+ /** Returns a normal source that provides normals sourced from the the normal map argument.
+ Not to be used as part of the API yet. Used internally by SkLightingShader.
+
+ @param normal the normal map
+ @param invNormRotation rotation applied to the normal map's normals
+ @param normLocalM the local matrix for the normal map
+
+ nullptr will be returned if
+ 'normal' is empty
+ 'normal' too big (> 65535 on either side)
+
+ The normal map is currently assumed to be an 8888 image where the normal at a texel
+ is retrieved by:
+ N.x = R-127;
+ N.y = G-127;
+ N.z = B-127;
+ N.normalize();
+ The +Z axis is thus encoded in RGB as (127, 127, 255) while the -Z axis is
+ (127, 127, 0).
+ */
+ static sk_sp<NormalSource> MakeMap(const SkBitmap& normal, const SkVector& invNormRotation,
+ const SkMatrix* normLocalM);
+
+ SK_DEFINE_FLATTENABLE_TYPE(NormalSource)
+ SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
+ };
+
+
+
/** Returns a shader that lights the diffuse and normal maps with a set of lights.
It returns a shader with a reference count of 1.
@param normal the normal map
@param lights the lights applied to the normal map
@param invNormRotation rotation applied to the normal map's normals
- @param diffLocalMatrix the local matrix for the diffuse map (transform from
- texture coordinates to shape source coordinates). nullptr is
- interpreted as an identity matrix.
- @param normLocalMatrix the local matrix for the normal map (transform from
- texture coordinates to shape source coordinates). nullptr is
- interpreted as an identity matrix.
+ @param diffLocalMatrix the local matrix for the diffuse texture
+ @param normLocalMatrix the local matrix for the normal map
nullptr will be returned if:
either 'diffuse' or 'normal' are empty
--- /dev/null
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmapProcShader.h"
+#include "SkError.h"
+#include "SkErrorInternals.h"
+#include "SkLightingShader.h"
+#include "SkReadBuffer.h"
+#include "SkWriteBuffer.h"
+
+// Genretating vtable
+SkLightingShader::NormalSource::~NormalSource() {}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class NormalMapSourceImpl : public SkLightingShader::NormalSource {
+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();
+ }
+
+#if SK_SUPPORT_GPU
+ sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*,
+ const SkMatrix& viewM,
+ const SkMatrix* localMatrix,
+ SkFilterQuality,
+ SkSourceGammaTreatment) const override;
+#endif
+
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(NormalMapSourceImpl)
+
+protected:
+ void flatten(SkWriteBuffer& buf) const override;
+
+private:
+ SkBitmap fNormalMap;
+ SkMatrix fNormLocalMatrix;
+ SkVector fInvNormRotation;
+
+ friend class SkLightingShader::NormalSource;
+
+ typedef SkLightingShader::NormalSource INHERITED;
+};
+
+////////////////////////////////////////////////////////////////////////////
+
+#if SK_SUPPORT_GPU
+
+#include "GrCoordTransform.h"
+#include "GrInvariantOutput.h"
+#include "GrTextureParams.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "SkGr.h"
+
+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);
+
+ this->initClassID<NormalMapFP>();
+ }
+
+ class GLSLNormalMapFP : public GrGLSLFragmentProcessor {
+ public:
+ GLSLNormalMapFP() {
+ fInvNormRotation.set(0.0f, 0.0f);
+ }
+
+ void emitCode(EmitArgs& args) override {
+
+ GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
+ GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
+
+ // add uniform
+ const char* xformUniName = nullptr;
+ fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
+ 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);");
+
+ // TODO: inverse map the light direction vectors in the vertex shader rather than
+ // transforming all the normals here!
+ fragBuilder->codeAppendf(
+ "mat3 m = mat3(%s.x, -%s.y, 0.0, %s.y, %s.x, 0.0, 0.0, 0.0, 1.0);",
+ xformUniName, xformUniName, xformUniName, xformUniName);
+
+ fragBuilder->codeAppend("normal = normalize(m*normal);");
+ fragBuilder->codeAppendf("%s = vec4(normal, 0);", args.fOutputColor);
+ }
+
+ static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
+ GrProcessorKeyBuilder* b) {
+ b->add32(0x0);
+ }
+
+ protected:
+ void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
+ const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
+
+ const SkVector& invNormRotation = normalMapFP.invNormRotation();
+ if (invNormRotation != fInvNormRotation) {
+ pdman.set2fv(fXformUni, 1, &invNormRotation.fX);
+ fInvNormRotation = invNormRotation;
+ }
+ }
+
+ private:
+ SkVector fInvNormRotation;
+ GrGLSLProgramDataManager::UniformHandle fXformUni;
+ };
+
+ void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
+ GLSLNormalMapFP::GenKey(*this, caps, b);
+ }
+
+ const char* name() const override { return "NormalMapFP"; }
+
+ void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
+ inout->setToUnknown(GrInvariantOutput::ReadInput::kWillNot_ReadInput);
+ }
+
+ const SkVector& invNormRotation() const { return fInvNormRotation; }
+
+private:
+ GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalMapFP; }
+
+ bool onIsEqual(const GrFragmentProcessor& proc) const override {
+ const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
+ return fNormDeviceTransform == normalMapFP.fNormDeviceTransform &&
+ fNormalTextureAccess == normalMapFP.fNormalTextureAccess &&
+ fInvNormRotation == normalMapFP.fInvNormRotation;
+ }
+
+ GrCoordTransform fNormDeviceTransform;
+ GrTextureAccess fNormalTextureAccess;
+ 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,
+ const SkMatrix *localMatrix,
+ 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
+
+ SkMatrix normM;
+ if (!make_mat(fNormalMap, fNormLocalMatrix, localMatrix, &normM)) {
+ 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.");
+ return nullptr;
+ }
+
+ return sk_make_sp<NormalMapFP>(normalTexture, normM, normParams, fInvNormRotation);
+}
+
+#endif // SK_SUPPORT_GPU
+
+////////////////////////////////////////////////////////////////////////////
+
+sk_sp<SkFlattenable> NormalMapSourceImpl::CreateProc(SkReadBuffer& buf) {
+
+ SkMatrix normLocalM;
+ bool hasNormLocalM = buf.readBool();
+ if (hasNormLocalM) {
+ buf.readMatrix(&normLocalM);
+ } else {
+ normLocalM.reset();
+ }
+
+ SkBitmap normal;
+ if (!buf.readBitmap(&normal)) {
+ return nullptr;
+ }
+ normal.setImmutable();
+
+ SkVector invNormRotation = {1,0};
+ if (!buf.isVersionLT(SkReadBuffer::kLightingShaderWritesInvNormRotation)) {
+ invNormRotation = buf.readPoint();
+ }
+
+ return sk_make_sp<NormalMapSourceImpl>(normal, invNormRotation, &normLocalM);
+}
+
+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.writePoint(fInvNormRotation);
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+sk_sp<SkLightingShader::NormalSource> SkLightingShader::NormalSource::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);
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingShader::NormalSource)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(NormalMapSourceImpl)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
+
+////////////////////////////////////////////////////////////////////////////
+++ /dev/null
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkError.h"
-#include "SkErrorInternals.h"
-#include "SkLightingShader.h"
-#include "SkNormalSource.h"
-#include "SkReadBuffer.h"
-#include "SkWriteBuffer.h"
-
-// Genretating vtable
-SkNormalSource::~SkNormalSource() {}
-
-///////////////////////////////////////////////////////////////////////////////
-
-class NormalMapSourceImpl : public SkNormalSource {
-public:
- NormalMapSourceImpl(sk_sp<SkShader> mapShader, const SkVector &normRotation)
- : fMapShader(std::move(mapShader))
- , fNormRotation(normRotation) {}
-
-#if SK_SUPPORT_GPU
- sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*,
- const SkMatrix& viewM,
- const SkMatrix* localMatrix,
- SkFilterQuality,
- 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:
- class Provider : public SkNormalSource::Provider {
- public:
- Provider(const NormalMapSourceImpl& source, SkShader::Context* fMapContext);
-
- virtual ~Provider() override;
-
- void fillScanLine(int x, int y, SkPoint3 output[], int count) const override;
- private:
- const NormalMapSourceImpl& fSource;
- SkShader::Context* fMapContext;
-
- typedef SkNormalSource::Provider INHERITED;
- };
-
- sk_sp<SkShader> fMapShader;
- SkVector fNormRotation;
-
- friend class SkNormalSource;
-
- typedef SkNormalSource INHERITED;
-};
-
-////////////////////////////////////////////////////////////////////////////
-
-#if SK_SUPPORT_GPU
-
-#include "GrCoordTransform.h"
-#include "GrInvariantOutput.h"
-#include "GrTextureParams.h"
-#include "glsl/GrGLSLFragmentProcessor.h"
-#include "glsl/GrGLSLFragmentShaderBuilder.h"
-#include "SkGr.h"
-
-class NormalMapFP : public GrFragmentProcessor {
-public:
- NormalMapFP(sk_sp<GrFragmentProcessor> mapFP, const SkVector& normRotation)
- : fNormRotation(normRotation) {
- this->registerChildProcessor(mapFP);
-
- this->initClassID<NormalMapFP>();
- }
-
- class GLSLNormalMapFP : public GrGLSLFragmentProcessor {
- public:
- GLSLNormalMapFP() {
- fNormRotation.set(0.0f, 0.0f);
- }
-
- void emitCode(EmitArgs& args) override {
-
- GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
- GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
-
- // add uniform
- const char* xformUniName = nullptr;
- fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
- kVec2f_GrSLType, kDefault_GrSLPrecision,
- "Xform", &xformUniName);
-
- 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!
- fragBuilder->codeAppendf(
- "mat3 m = mat3(%s.x, -%s.y, 0.0, %s.y, %s.x, 0.0, 0.0, 0.0, 1.0);",
- xformUniName, xformUniName, xformUniName, xformUniName);
-
- fragBuilder->codeAppend("normal = normalize(m*normal);");
- fragBuilder->codeAppendf("%s = vec4(normal, 0);", args.fOutputColor);
- }
-
- static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
- GrProcessorKeyBuilder* b) {
- b->add32(0x0);
- }
-
- protected:
- void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
- const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
-
- const SkVector& normRotation = normalMapFP.normRotation();
- if (normRotation != fNormRotation) {
- pdman.set2fv(fXformUni, 1, &normRotation.fX);
- fNormRotation = normRotation;
- }
- }
-
- private:
- SkVector fNormRotation;
- GrGLSLProgramDataManager::UniformHandle fXformUni;
- };
-
- void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
- GLSLNormalMapFP::GenKey(*this, caps, b);
- }
-
- const char* name() const override { return "NormalMapFP"; }
-
- void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
- inout->setToUnknown(GrInvariantOutput::ReadInput::kWillNot_ReadInput);
- }
-
- const SkVector& normRotation() const { return fNormRotation; }
-
-private:
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalMapFP; }
-
- bool onIsEqual(const GrFragmentProcessor& proc) const override {
- const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
- return fNormRotation == normalMapFP.fNormRotation;
- }
-
- SkVector fNormRotation;
-};
-
-sk_sp<GrFragmentProcessor> NormalMapSourceImpl::asFragmentProcessor(
- GrContext *context,
- const SkMatrix &viewM,
- const SkMatrix *localMatrix,
- SkFilterQuality filterQuality,
- SkSourceGammaTreatment gammaTreatment) const {
-
- sk_sp<GrFragmentProcessor> mapFP = fMapShader->asFragmentProcessor(context, viewM,
- localMatrix, filterQuality, gammaTreatment);
-
- return sk_make_sp<NormalMapFP>(std::move(mapFP), fNormRotation);
-}
-
-#endif // SK_SUPPORT_GPU
-
-////////////////////////////////////////////////////////////////////////////
-
-NormalMapSourceImpl::Provider::Provider(const NormalMapSourceImpl& source,
- SkShader::Context* mapContext)
- : fSource(source)
- , fMapContext(mapContext) {
-}
-
-NormalMapSourceImpl::Provider::~Provider() {
- fMapContext->~Context();
-}
-
-SkNormalSource::Provider* NormalMapSourceImpl::asProvider(
- const SkShader::ContextRec &rec, void *storage) const {
- SkMatrix normTotalInv;
- if (!this->computeNormTotalInverse(rec, &normTotalInv)) {
- return nullptr;
- }
-
- void* mapContextStorage = (char*)storage + sizeof(Provider);
- SkShader::Context* context = fMapShader->createContext(rec, mapContextStorage);
- if (!context) {
- return nullptr;
- }
-
- return new (storage) Provider(*this, context);
-}
-
-size_t NormalMapSourceImpl::providerSize(const SkShader::ContextRec& rec) const {
- return sizeof(Provider) + fMapShader->contextSize(rec);
-}
-
-bool NormalMapSourceImpl::computeNormTotalInverse(const SkShader::ContextRec& rec,
- SkMatrix* normTotalInverse) const {
- SkMatrix total;
- total.setConcat(*rec.fMatrix, fMapShader->getLocalMatrix());
-
- const SkMatrix* m = &total;
- if (rec.fLocalMatrix) {
- total.setConcat(*m, *rec.fLocalMatrix);
- m = &total;
- }
- return m->invert(normTotalInverse);
-}
-
-#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);
-
- fMapContext->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.fNormRotation.fX * tempNorm.fX +
- fSource.fNormRotation.fY * tempNorm.fY;
- output[i].fY = -fSource.fNormRotation.fY * tempNorm.fX +
- fSource.fNormRotation.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> mapShader = buf.readFlattenable<SkShader>();
-
- SkVector normRotation = {1,0};
- if (!buf.isVersionLT(SkReadBuffer::kLightingShaderWritesInvNormRotation)) {
- normRotation = buf.readPoint();
- }
-
- return sk_make_sp<NormalMapSourceImpl>(std::move(mapShader), normRotation);
-}
-
-void NormalMapSourceImpl::flatten(SkWriteBuffer& buf) const {
- this->INHERITED::flatten(buf);
-
- buf.writeFlattenable(fMapShader.get());
- buf.writePoint(fNormRotation);
-}
-
-////////////////////////////////////////////////////////////////////////////
-
-sk_sp<SkNormalSource> SkNormalSource::MakeFromNormalMap(sk_sp<SkShader> map,
- const SkVector &normRotation) {
- SkASSERT(SkScalarNearlyEqual(normRotation.lengthSqd(), SK_Scalar1));
- if (!map) {
- return nullptr;
- }
-
- return sk_make_sp<NormalMapSourceImpl>(std::move(map), normRotation);
-}
-
-////////////////////////////////////////////////////////////////////////////
-
-SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkNormalSource)
- SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(NormalMapSourceImpl)
-SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
-
-////////////////////////////////////////////////////////////////////////////
+++ /dev/null
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkNormalSource_DEFINED
-#define SkNormalSource_DEFINED
-
-#include "SkFlattenable.h"
-
-/** Abstract class that generates or reads in normals for use by SkLightingShader. Not to be
- used as part of the API yet. Used internally by SkLightingShader.
-*/
-class SK_API SkNormalSource : public SkFlattenable {
-public:
- virtual ~SkNormalSource() override;
-
-#if SK_SUPPORT_GPU
- /** Returns a fragment processor that takes no input and outputs a normal (already rotated)
- as its output color. To be used as a child fragment processor.
- */
- virtual sk_sp<GrFragmentProcessor> asFragmentProcessor(
- GrContext* context,
- const SkMatrix& viewM,
- const SkMatrix* localMatrix,
- SkFilterQuality filterQuality,
- SkSourceGammaTreatment gammaTreatment) const = 0;
-#endif
-
- class Provider {
- public:
- virtual ~Provider() {};
-
- /** Called for each span of the object being drawn on the CPU. Your subclass should set
- the appropriate normals that correspond to the specified device coordinates.
- */
- virtual void fillScanLine(int x, int y, SkPoint3 output[], int count) const = 0;
- };
-
- /** Returns an instance of 'Provider' that provides normals for the CPU pipeline. The
- necessary data will be initialized in place at 'storage'.
- */
- virtual Provider* asProvider(const SkShader::ContextRec&, void* storage) const = 0;
-
- /** Amount of memory needed to store a provider object and its dependencies.
- */
- virtual size_t providerSize(const SkShader::ContextRec&) const = 0;
-
- /** Returns a normal source that provides normals sourced from the the normal map argument.
- Not to be used as part of the API yet. Used internally by SkLightingShader.
-
- @param map a shader that outputs the normal map
- @param normRotation rotation applied to the normal map's normals, in the
- [cos a, sin a] form.
-
- nullptr will be returned if 'map' is null
-
- The normal map is currently assumed to be an 8888 image where the normal at a texel
- is retrieved by:
- N.x = R-127;
- N.y = G-127;
- N.z = B-127;
- N.normalize();
- The +Z axis is thus encoded in RGB as (127, 127, 255) while the -Z axis is
- (127, 127, 0).
- */
- static sk_sp<SkNormalSource> MakeFromNormalMap(sk_sp<SkShader> map,
- const SkVector& normRotation);
-
- SK_DEFINE_FLATTENABLE_TYPE(SkNormalSource)
- SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
-};
-
-#endif
#include "SkMatrixConvolutionImageFilter.h"
#include "SkMergeImageFilter.h"
#include "SkMorphologyImageFilter.h"
-#include "SkNormalSource.h"
#include "SkOffsetImageFilter.h"
#include "SkPaintImageFilter.h"
#include "SkPerlinNoiseShader.h"
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPerlinNoiseShader)
SkGradientShader::InitializeFlattenables();
SkLightingShader::InitializeFlattenables();
- SkNormalSource::InitializeFlattenables();
+ SkLightingShader::NormalSource::InitializeFlattenables();
// PathEffect