Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2016 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkNormalMapSource.h"
      9 
     10 #include "SkArenaAlloc.h"
     11 #include "SkLightingShader.h"
     12 #include "SkMatrix.h"
     13 #include "SkNormalSource.h"
     14 #include "SkNormalSourcePriv.h"
     15 #include "SkPM4f.h"
     16 #include "SkReadBuffer.h"
     17 #include "SkWriteBuffer.h"
     18 
     19 #if SK_SUPPORT_GPU
     20 #include "GrCoordTransform.h"
     21 #include "GrSamplerParams.h"
     22 #include "glsl/GrGLSLFragmentProcessor.h"
     23 #include "glsl/GrGLSLFragmentShaderBuilder.h"
     24 #include "SkGr.h"
     25 
     26 class NormalMapFP : public GrFragmentProcessor {
     27 public:
     28     NormalMapFP(sk_sp<GrFragmentProcessor> mapFP, const SkMatrix& invCTM)
     29             : INHERITED(kNone_OptimizationFlags), fInvCTM(invCTM) {
     30         this->registerChildProcessor(mapFP);
     31 
     32         this->initClassID<NormalMapFP>();
     33     }
     34 
     35     class GLSLNormalMapFP : public GLSLNormalFP {
     36     public:
     37         GLSLNormalMapFP()
     38             : fColumnMajorInvCTM22{0.0f} {}
     39 
     40         void onEmitCode(EmitArgs& args) override {
     41             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
     42             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
     43 
     44             // add uniform
     45             const char* xformUniName = nullptr;
     46             fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kMat22f_GrSLType,
     47                                                    kDefault_GrSLPrecision, "Xform", &xformUniName);
     48 
     49             SkString dstNormalColorName("dstNormalColor");
     50             this->emitChild(0, nullptr, &dstNormalColorName, args);
     51             fragBuilder->codeAppendf("vec3 normal = normalize(%s.rgb - vec3(0.5));",
     52                                      dstNormalColorName.c_str());
     53 
     54             // If there's no x & y components, return (0, 0, +/- 1) instead to avoid division by 0
     55             fragBuilder->codeAppend( "if (abs(normal.z) > 0.999) {");
     56             fragBuilder->codeAppendf("    %s = normalize(vec4(0.0, 0.0, normal.z, 0.0));",
     57                     args.fOutputColor);
     58             // Else, Normalizing the transformed X and Y, while keeping constant both Z and the
     59             // vector's angle in the XY plane. This maintains the "slope" for the surface while
     60             // appropriately rotating the normal regardless of any anisotropic scaling that occurs.
     61             // Here, we call 'scaling factor' the number that must divide the transformed X and Y so
     62             // that the normal's length remains equal to 1.
     63             fragBuilder->codeAppend( "} else {");
     64             fragBuilder->codeAppendf("    vec2 transformed = %s * normal.xy;",
     65                     xformUniName);
     66             fragBuilder->codeAppend( "    float scalingFactorSquared = "
     67                                                  "( (transformed.x * transformed.x) "
     68                                                    "+ (transformed.y * transformed.y) )"
     69                                                  "/(1.0 - (normal.z * normal.z));");
     70             fragBuilder->codeAppendf("    %s = vec4(transformed*inversesqrt(scalingFactorSquared),"
     71                                                    "normal.z, 0.0);",
     72                     args.fOutputColor);
     73             fragBuilder->codeAppend( "}");
     74         }
     75 
     76         static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
     77             b->add32(0x0);
     78         }
     79 
     80     protected:
     81         void setNormalData(const GrGLSLProgramDataManager& pdman,
     82                            const GrProcessor& proc) override {
     83             const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
     84 
     85             const SkMatrix& invCTM = normalMapFP.invCTM();
     86             fColumnMajorInvCTM22[0] = invCTM.get(SkMatrix::kMScaleX);
     87             fColumnMajorInvCTM22[1] = invCTM.get(SkMatrix::kMSkewY);
     88             fColumnMajorInvCTM22[2] = invCTM.get(SkMatrix::kMSkewX);
     89             fColumnMajorInvCTM22[3] = invCTM.get(SkMatrix::kMScaleY);
     90             pdman.setMatrix2f(fXformUni, fColumnMajorInvCTM22);
     91         }
     92 
     93     private:
     94         // Upper-right 2x2 corner of the inverse of the CTM in column-major form
     95         float fColumnMajorInvCTM22[4];
     96         GrGLSLProgramDataManager::UniformHandle fXformUni;
     97     };
     98 
     99     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
    100         GLSLNormalMapFP::GenKey(*this, caps, b);
    101     }
    102 
    103     const char* name() const override { return "NormalMapFP"; }
    104 
    105     const SkMatrix& invCTM() const { return fInvCTM; }
    106 
    107 private:
    108     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalMapFP; }
    109 
    110     bool onIsEqual(const GrFragmentProcessor& proc) const override {
    111         const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
    112         return fInvCTM == normalMapFP.fInvCTM;
    113     }
    114 
    115     SkMatrix fInvCTM;
    116 
    117     typedef GrFragmentProcessor INHERITED;
    118 };
    119 
    120 sk_sp<GrFragmentProcessor> SkNormalMapSourceImpl::asFragmentProcessor(
    121         const SkShader::AsFPArgs& args) const {
    122     sk_sp<GrFragmentProcessor> mapFP = fMapShader->asFragmentProcessor(args);
    123     if (!mapFP) {
    124         return nullptr;
    125     }
    126 
    127     return sk_make_sp<NormalMapFP>(std::move(mapFP), fInvCTM);
    128 }
    129 
    130 #endif // SK_SUPPORT_GPU
    131 
    132 ////////////////////////////////////////////////////////////////////////////
    133 
    134 SkNormalMapSourceImpl::Provider::Provider(const SkNormalMapSourceImpl& source,
    135                                           SkShader::Context* mapContext)
    136     : fSource(source)
    137     , fMapContext(mapContext) {}
    138 
    139 SkNormalSource::Provider* SkNormalMapSourceImpl::asProvider(const SkShader::ContextRec &rec,
    140                                                             SkArenaAlloc* alloc) const {
    141     SkMatrix normTotalInv;
    142     if (!this->computeNormTotalInverse(rec, &normTotalInv)) {
    143         return nullptr;
    144     }
    145 
    146     // Overriding paint's alpha because we need the normal map's RGB channels to be unpremul'd
    147     SkPaint overridePaint {*(rec.fPaint)};
    148     overridePaint.setAlpha(0xFF);
    149     SkShader::ContextRec overrideRec(overridePaint, *(rec.fMatrix), rec.fLocalMatrix,
    150                                      rec.fPreferredDstType, rec.fDstColorSpace);
    151 
    152     SkShader::Context* context = fMapShader->makeContext(overrideRec, alloc);
    153     if (!context) {
    154         return nullptr;
    155     }
    156 
    157     return alloc->make<Provider>(*this, context);
    158 }
    159 
    160 bool SkNormalMapSourceImpl::computeNormTotalInverse(const SkShader::ContextRec& rec,
    161                                                     SkMatrix* normTotalInverse) const {
    162     SkMatrix total = SkMatrix::Concat(*rec.fMatrix, fMapShader->getLocalMatrix());
    163     if (rec.fLocalMatrix) {
    164         total.preConcat(*rec.fLocalMatrix);
    165     }
    166 
    167     return total.invert(normTotalInverse);
    168 }
    169 
    170 #define BUFFER_MAX 16
    171 void SkNormalMapSourceImpl::Provider::fillScanLine(int x, int y, SkPoint3 output[],
    172                                                    int count) const {
    173     SkPMColor tmpNormalColors[BUFFER_MAX];
    174 
    175     do {
    176         int n = SkTMin(count, BUFFER_MAX);
    177 
    178         fMapContext->shadeSpan(x, y, tmpNormalColors, n);
    179 
    180         for (int i = 0; i < n; i++) {
    181             SkPoint3 tempNorm;
    182 
    183             tempNorm.set(SkIntToScalar(SkGetPackedR32(tmpNormalColors[i])) - 127.0f,
    184                          SkIntToScalar(SkGetPackedG32(tmpNormalColors[i])) - 127.0f,
    185                          SkIntToScalar(SkGetPackedB32(tmpNormalColors[i])) - 127.0f);
    186 
    187             tempNorm.normalize();
    188 
    189 
    190             if (!SkScalarNearlyEqual(SkScalarAbs(tempNorm.fZ), 1.0f)) {
    191                 SkVector transformed = fSource.fInvCTM.mapVector(tempNorm.fX, tempNorm.fY);
    192 
    193                 // Normalizing the transformed X and Y, while keeping constant both Z and the
    194                 // vector's angle in the XY plane. This maintains the "slope" for the surface while
    195                 // appropriately rotating the normal for any anisotropic scaling that occurs.
    196                 // Here, we call scaling factor the number that must divide the transformed X and Y
    197                 // so that the normal's length remains equal to 1.
    198                 SkScalar scalingFactorSquared =
    199                         (SkScalarSquare(transformed.fX) + SkScalarSquare(transformed.fY))
    200                         / (1.0f - SkScalarSquare(tempNorm.fZ));
    201                 SkScalar invScalingFactor = SkScalarInvert(SkScalarSqrt(scalingFactorSquared));
    202 
    203                 output[i].fX = transformed.fX * invScalingFactor;
    204                 output[i].fY = transformed.fY * invScalingFactor;
    205                 output[i].fZ = tempNorm.fZ;
    206             } else {
    207                 output[i] = {0.0f, 0.0f, tempNorm.fZ};
    208                 output[i].normalize();
    209             }
    210 
    211             SkASSERT(SkScalarNearlyEqual(output[i].length(), 1.0f));
    212         }
    213 
    214         output += n;
    215         x += n;
    216         count -= n;
    217     } while (count > 0);
    218 }
    219 
    220 ////////////////////////////////////////////////////////////////////////////////
    221 
    222 sk_sp<SkFlattenable> SkNormalMapSourceImpl::CreateProc(SkReadBuffer& buf) {
    223 
    224     sk_sp<SkShader> mapShader = buf.readFlattenable<SkShader>();
    225 
    226     SkMatrix invCTM;
    227     buf.readMatrix(&invCTM);
    228 
    229     return sk_make_sp<SkNormalMapSourceImpl>(std::move(mapShader), invCTM);
    230 }
    231 
    232 void SkNormalMapSourceImpl::flatten(SkWriteBuffer& buf) const {
    233     this->INHERITED::flatten(buf);
    234 
    235     buf.writeFlattenable(fMapShader.get());
    236     buf.writeMatrix(fInvCTM);
    237 }
    238 
    239 ////////////////////////////////////////////////////////////////////////////
    240 
    241 sk_sp<SkNormalSource> SkNormalSource::MakeFromNormalMap(sk_sp<SkShader> map, const SkMatrix& ctm) {
    242     SkMatrix invCTM;
    243 
    244     if (!ctm.invert(&invCTM) || !map) {
    245         return nullptr;
    246     }
    247 
    248     return sk_make_sp<SkNormalMapSourceImpl>(std::move(map), invCTM);
    249 }
    250