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:
NormalMapFP(sk_sp<GrFragmentProcessor> mapFP,const SkMatrix & invCTM)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:
GLSLNormalMapFP()37         GLSLNormalMapFP()
38             : fColumnMajorInvCTM22{0.0f} {}
39 
onEmitCode(EmitArgs & args)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 
GenKey(const GrProcessor &,const GrShaderCaps &,GrProcessorKeyBuilder * b)76         static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
77             b->add32(0x0);
78         }
79 
80     protected:
setNormalData(const GrGLSLProgramDataManager & pdman,const GrProcessor & proc)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 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const99     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
100         GLSLNormalMapFP::GenKey(*this, caps, b);
101     }
102 
name() const103     const char* name() const override { return "NormalMapFP"; }
104 
invCTM() const105     const SkMatrix& invCTM() const { return fInvCTM; }
106 
107 private:
onCreateGLSLInstance() const108     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalMapFP; }
109 
onIsEqual(const GrFragmentProcessor & proc) const110     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 
asFragmentProcessor(const SkShader::AsFPArgs & args) const120 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 
Provider(const SkNormalMapSourceImpl & source,SkShader::Context * mapContext)134 SkNormalMapSourceImpl::Provider::Provider(const SkNormalMapSourceImpl& source,
135                                           SkShader::Context* mapContext)
136     : fSource(source)
137     , fMapContext(mapContext) {}
138 
asProvider(const SkShader::ContextRec & rec,SkArenaAlloc * alloc) const139 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 
computeNormTotalInverse(const SkShader::ContextRec & rec,SkMatrix * normTotalInverse) const160 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
fillScanLine(int x,int y,SkPoint3 output[],int count) const171 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 
CreateProc(SkReadBuffer & buf)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 
flatten(SkWriteBuffer & buf) const232 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 
MakeFromNormalMap(sk_sp<SkShader> map,const SkMatrix & ctm)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