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