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