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