1 2/* 3 * Copyright 2015 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9#include "SkBitmapProcState.h" 10#include "SkColor.h" 11#include "SkEmptyShader.h" 12#include "SkErrorInternals.h" 13#include "SkLightingShader.h" 14#include "SkMathPriv.h" 15#include "SkPoint3.h" 16#include "SkReadBuffer.h" 17#include "SkWriteBuffer.h" 18 19//////////////////////////////////////////////////////////////////////////// 20 21/* 22 SkLightingShader TODOs: 23 support other than clamp mode 24 allow 'diffuse' & 'normal' to be of different dimensions? 25 support different light types 26 support multiple lights 27 enforce normal map is 4 channel 28 use SkImages instead if SkBitmaps 29 30 To Test: 31 non-opaque diffuse textures 32 A8 diffuse textures 33 down & upsampled draws 34*/ 35 36 37 38/** \class SkLightingShaderImpl 39 This subclass of shader applies lighting. 40*/ 41class SK_API SkLightingShaderImpl : public SkShader { 42public: 43 44 /** Create a new lighting shader that uses the provided normal map and 45 lights to light the diffuse bitmap. 46 @param diffuse the diffuse bitmap 47 @param normal the normal map 48 @param lights the lights applied to the normal map 49 @param invNormRotation rotation applied to the normal map's normals 50 @param diffLocalM the local matrix for the diffuse coordinates 51 @param normLocalM the local matrix for the normal coordinates 52 */ 53 SkLightingShaderImpl(const SkBitmap& diffuse, const SkBitmap& normal, 54 const SkLightingShader::Lights* lights, 55 const SkVector& invNormRotation, 56 const SkMatrix* diffLocalM, const SkMatrix* normLocalM) 57 : INHERITED(diffLocalM) 58 , fDiffuseMap(diffuse) 59 , fNormalMap(normal) 60 , fLights(SkRef(lights)) 61 , fInvNormRotation(invNormRotation) { 62 63 if (normLocalM) { 64 fNormLocalMatrix = *normLocalM; 65 } else { 66 fNormLocalMatrix.reset(); 67 } 68 // Pre-cache so future calls to fNormLocalMatrix.getType() are threadsafe. 69 (void)fNormLocalMatrix.getType(); 70 71 } 72 73 bool isOpaque() const override; 74 75#if SK_SUPPORT_GPU 76 const GrFragmentProcessor* asFragmentProcessor(GrContext*, 77 const SkMatrix& viewM, 78 const SkMatrix* localMatrix, 79 SkFilterQuality) const override; 80#endif 81 82 size_t contextSize(const ContextRec&) const override; 83 84 class LightingShaderContext : public SkShader::Context { 85 public: 86 // The context takes ownership of the states. It will call their destructors 87 // but will NOT free the memory. 88 LightingShaderContext(const SkLightingShaderImpl&, const ContextRec&, 89 SkBitmapProcState* diffuseState, SkBitmapProcState* normalState); 90 ~LightingShaderContext() override; 91 92 void shadeSpan(int x, int y, SkPMColor[], int count) override; 93 94 uint32_t getFlags() const override { return fFlags; } 95 96 private: 97 SkBitmapProcState* fDiffuseState; 98 SkBitmapProcState* fNormalState; 99 uint32_t fFlags; 100 101 typedef SkShader::Context INHERITED; 102 }; 103 104 SK_TO_STRING_OVERRIDE() 105 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLightingShaderImpl) 106 107protected: 108 void flatten(SkWriteBuffer&) const override; 109 Context* onCreateContext(const ContextRec&, void*) const override; 110 bool computeNormTotalInverse(const ContextRec& rec, SkMatrix* normTotalInverse) const; 111 112private: 113 SkBitmap fDiffuseMap; 114 SkBitmap fNormalMap; 115 116 SkAutoTUnref<const SkLightingShader::Lights> fLights; 117 118 SkMatrix fNormLocalMatrix; 119 SkVector fInvNormRotation; 120 121 friend class SkLightingShader; 122 123 typedef SkShader INHERITED; 124}; 125 126//////////////////////////////////////////////////////////////////////////// 127 128#if SK_SUPPORT_GPU 129 130#include "GrCoordTransform.h" 131#include "GrFragmentProcessor.h" 132#include "GrInvariantOutput.h" 133#include "GrTextureAccess.h" 134#include "glsl/GrGLSLFragmentProcessor.h" 135#include "glsl/GrGLSLFragmentShaderBuilder.h" 136#include "glsl/GrGLSLProgramDataManager.h" 137#include "glsl/GrGLSLUniformHandler.h" 138#include "SkGr.h" 139#include "SkGrPriv.h" 140 141class LightingFP : public GrFragmentProcessor { 142public: 143 LightingFP(GrTexture* diffuse, GrTexture* normal, const SkMatrix& diffMatrix, 144 const SkMatrix& normMatrix, const GrTextureParams& diffParams, 145 const GrTextureParams& normParams, const SkLightingShader::Lights* lights, 146 const SkVector& invNormRotation) 147 : fDiffDeviceTransform(kLocal_GrCoordSet, diffMatrix, diffuse, diffParams.filterMode()) 148 , fNormDeviceTransform(kLocal_GrCoordSet, normMatrix, normal, normParams.filterMode()) 149 , fDiffuseTextureAccess(diffuse, diffParams) 150 , fNormalTextureAccess(normal, normParams) 151 , fInvNormRotation(invNormRotation) { 152 this->addCoordTransform(&fDiffDeviceTransform); 153 this->addCoordTransform(&fNormDeviceTransform); 154 this->addTextureAccess(&fDiffuseTextureAccess); 155 this->addTextureAccess(&fNormalTextureAccess); 156 157 // fuse all ambient lights into a single one 158 fAmbientColor.set(0.0f, 0.0f, 0.0f); 159 for (int i = 0; i < lights->numLights(); ++i) { 160 if (SkLight::kAmbient_LightType == lights->light(i).type()) { 161 fAmbientColor += lights->light(i).color(); 162 } else { 163 // TODO: handle more than one of these 164 fLightColor = lights->light(i).color(); 165 fLightDir = lights->light(i).dir(); 166 } 167 } 168 169 this->initClassID<LightingFP>(); 170 } 171 172 class LightingGLFP : public GrGLSLFragmentProcessor { 173 public: 174 LightingGLFP() { 175 fLightDir.fX = 10000.0f; 176 fLightColor.fX = 0.0f; 177 fAmbientColor.fX = 0.0f; 178 fInvNormRotation.set(0.0f, 0.0f); 179 } 180 181 void emitCode(EmitArgs& args) override { 182 183 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; 184 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 185 186 // add uniforms 187 const char* lightDirUniName = nullptr; 188 fLightDirUni = uniformHandler->addUniform(kFragment_GrShaderFlag, 189 kVec3f_GrSLType, kDefault_GrSLPrecision, 190 "LightDir", &lightDirUniName); 191 192 const char* lightColorUniName = nullptr; 193 fLightColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag, 194 kVec3f_GrSLType, kDefault_GrSLPrecision, 195 "LightColor", &lightColorUniName); 196 197 const char* ambientColorUniName = nullptr; 198 fAmbientColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag, 199 kVec3f_GrSLType, kDefault_GrSLPrecision, 200 "AmbientColor", &ambientColorUniName); 201 202 const char* xformUniName = nullptr; 203 fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag, 204 kVec2f_GrSLType, kDefault_GrSLPrecision, 205 "Xform", &xformUniName); 206 207 fragBuilder->codeAppend("vec4 diffuseColor = "); 208 fragBuilder->appendTextureLookupAndModulate(args.fInputColor, args.fSamplers[0], 209 args.fCoords[0].c_str(), 210 args.fCoords[0].getType()); 211 fragBuilder->codeAppend(";"); 212 213 fragBuilder->codeAppend("vec4 normalColor = "); 214 fragBuilder->appendTextureLookup(args.fSamplers[1], 215 args.fCoords[1].c_str(), 216 args.fCoords[1].getType()); 217 fragBuilder->codeAppend(";"); 218 219 fragBuilder->codeAppend("vec3 normal = normalColor.rgb - vec3(0.5);"); 220 221 fragBuilder->codeAppendf( 222 "mat3 m = mat3(%s.x, -%s.y, 0.0, %s.y, %s.x, 0.0, 0.0, 0.0, 1.0);", 223 xformUniName, xformUniName, xformUniName, xformUniName); 224 225 // TODO: inverse map the light direction vectors in the vertex shader rather than 226 // transforming all the normals here! 227 fragBuilder->codeAppend("normal = normalize(m*normal);"); 228 229 fragBuilder->codeAppendf("float NdotL = clamp(dot(normal, %s), 0.0, 1.0);", 230 lightDirUniName); 231 // diffuse light 232 fragBuilder->codeAppendf("vec3 result = %s*diffuseColor.rgb*NdotL;", lightColorUniName); 233 // ambient light 234 fragBuilder->codeAppendf("result += %s;", ambientColorUniName); 235 fragBuilder->codeAppendf("%s = vec4(result.rgb, diffuseColor.a);", args.fOutputColor); 236 } 237 238 static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, 239 GrProcessorKeyBuilder* b) { 240// const LightingFP& lightingFP = proc.cast<LightingFP>(); 241 // only one shader generated currently 242 b->add32(0x0); 243 } 244 245 protected: 246 void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override { 247 const LightingFP& lightingFP = proc.cast<LightingFP>(); 248 249 const SkVector3& lightDir = lightingFP.lightDir(); 250 if (lightDir != fLightDir) { 251 pdman.set3fv(fLightDirUni, 1, &lightDir.fX); 252 fLightDir = lightDir; 253 } 254 255 const SkColor3f& lightColor = lightingFP.lightColor(); 256 if (lightColor != fLightColor) { 257 pdman.set3fv(fLightColorUni, 1, &lightColor.fX); 258 fLightColor = lightColor; 259 } 260 261 const SkColor3f& ambientColor = lightingFP.ambientColor(); 262 if (ambientColor != fAmbientColor) { 263 pdman.set3fv(fAmbientColorUni, 1, &ambientColor.fX); 264 fAmbientColor = ambientColor; 265 } 266 267 const SkVector& invNormRotation = lightingFP.invNormRotation(); 268 if (invNormRotation != fInvNormRotation) { 269 pdman.set2fv(fXformUni, 1, &invNormRotation.fX); 270 fInvNormRotation = invNormRotation; 271 } 272 } 273 274 private: 275 SkVector3 fLightDir; 276 GrGLSLProgramDataManager::UniformHandle fLightDirUni; 277 278 SkColor3f fLightColor; 279 GrGLSLProgramDataManager::UniformHandle fLightColorUni; 280 281 SkColor3f fAmbientColor; 282 GrGLSLProgramDataManager::UniformHandle fAmbientColorUni; 283 284 SkVector fInvNormRotation; 285 GrGLSLProgramDataManager::UniformHandle fXformUni; 286 }; 287 288 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { 289 LightingGLFP::GenKey(*this, caps, b); 290 } 291 292 const char* name() const override { return "LightingFP"; } 293 294 void onComputeInvariantOutput(GrInvariantOutput* inout) const override { 295 inout->mulByUnknownFourComponents(); 296 } 297 298 const SkVector3& lightDir() const { return fLightDir; } 299 const SkColor3f& lightColor() const { return fLightColor; } 300 const SkColor3f& ambientColor() const { return fAmbientColor; } 301 const SkVector& invNormRotation() const { return fInvNormRotation; } 302 303private: 304 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new LightingGLFP; } 305 306 bool onIsEqual(const GrFragmentProcessor& proc) const override { 307 const LightingFP& lightingFP = proc.cast<LightingFP>(); 308 return fDiffDeviceTransform == lightingFP.fDiffDeviceTransform && 309 fNormDeviceTransform == lightingFP.fNormDeviceTransform && 310 fDiffuseTextureAccess == lightingFP.fDiffuseTextureAccess && 311 fNormalTextureAccess == lightingFP.fNormalTextureAccess && 312 fLightDir == lightingFP.fLightDir && 313 fLightColor == lightingFP.fLightColor && 314 fAmbientColor == lightingFP.fAmbientColor && 315 fInvNormRotation == lightingFP.fInvNormRotation; 316 } 317 318 GrCoordTransform fDiffDeviceTransform; 319 GrCoordTransform fNormDeviceTransform; 320 GrTextureAccess fDiffuseTextureAccess; 321 GrTextureAccess fNormalTextureAccess; 322 SkVector3 fLightDir; 323 SkColor3f fLightColor; 324 SkColor3f fAmbientColor; 325 326 SkVector fInvNormRotation; 327}; 328 329//////////////////////////////////////////////////////////////////////////// 330 331static bool make_mat(const SkBitmap& bm, 332 const SkMatrix& localMatrix1, 333 const SkMatrix* localMatrix2, 334 SkMatrix* result) { 335 336 result->setIDiv(bm.width(), bm.height()); 337 338 SkMatrix lmInverse; 339 if (!localMatrix1.invert(&lmInverse)) { 340 return false; 341 } 342 if (localMatrix2) { 343 SkMatrix inv; 344 if (!localMatrix2->invert(&inv)) { 345 return false; 346 } 347 lmInverse.postConcat(inv); 348 } 349 result->preConcat(lmInverse); 350 351 return true; 352} 353 354const GrFragmentProcessor* SkLightingShaderImpl::asFragmentProcessor( 355 GrContext* context, 356 const SkMatrix& viewM, 357 const SkMatrix* localMatrix, 358 SkFilterQuality filterQuality) const { 359 // we assume diffuse and normal maps have same width and height 360 // TODO: support different sizes 361 SkASSERT(fDiffuseMap.width() == fNormalMap.width() && 362 fDiffuseMap.height() == fNormalMap.height()); 363 SkMatrix diffM, normM; 364 365 if (!make_mat(fDiffuseMap, this->getLocalMatrix(), localMatrix, &diffM)) { 366 return nullptr; 367 } 368 369 if (!make_mat(fNormalMap, fNormLocalMatrix, localMatrix, &normM)) { 370 return nullptr; 371 } 372 373 bool doBicubic; 374 GrTextureParams::FilterMode diffFilterMode = GrSkFilterQualityToGrFilterMode( 375 SkTMin(filterQuality, kMedium_SkFilterQuality), 376 viewM, 377 this->getLocalMatrix(), 378 &doBicubic); 379 SkASSERT(!doBicubic); 380 381 GrTextureParams::FilterMode normFilterMode = GrSkFilterQualityToGrFilterMode( 382 SkTMin(filterQuality, kMedium_SkFilterQuality), 383 viewM, 384 fNormLocalMatrix, 385 &doBicubic); 386 SkASSERT(!doBicubic); 387 388 // TODO: support other tile modes 389 GrTextureParams diffParams(kClamp_TileMode, diffFilterMode); 390 SkAutoTUnref<GrTexture> diffuseTexture(GrRefCachedBitmapTexture(context, 391 fDiffuseMap, diffParams)); 392 if (!diffuseTexture) { 393 SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture."); 394 return nullptr; 395 } 396 397 GrTextureParams normParams(kClamp_TileMode, normFilterMode); 398 SkAutoTUnref<GrTexture> normalTexture(GrRefCachedBitmapTexture(context, 399 fNormalMap, normParams)); 400 if (!normalTexture) { 401 SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture."); 402 return nullptr; 403 } 404 405 SkAutoTUnref<const GrFragmentProcessor> inner ( 406 new LightingFP(diffuseTexture, normalTexture, diffM, normM, diffParams, normParams, fLights, 407 fInvNormRotation)); 408 return GrFragmentProcessor::MulOutputByInputAlpha(inner); 409} 410 411#endif 412 413//////////////////////////////////////////////////////////////////////////// 414 415bool SkLightingShaderImpl::isOpaque() const { 416 return fDiffuseMap.isOpaque(); 417} 418 419size_t SkLightingShaderImpl::contextSize(const ContextRec&) const { 420 return 2 * sizeof(SkBitmapProcState) + sizeof(LightingShaderContext); 421} 422 423SkLightingShaderImpl::LightingShaderContext::LightingShaderContext(const SkLightingShaderImpl& shader, 424 const ContextRec& rec, 425 SkBitmapProcState* diffuseState, 426 SkBitmapProcState* normalState) 427 : INHERITED(shader, rec) 428 , fDiffuseState(diffuseState) 429 , fNormalState(normalState) 430{ 431 const SkPixmap& pixmap = fDiffuseState->fPixmap; 432 bool isOpaque = pixmap.isOpaque(); 433 434 // update fFlags 435 uint32_t flags = 0; 436 if (isOpaque && (255 == this->getPaintAlpha())) { 437 flags |= kOpaqueAlpha_Flag; 438 } 439 440 fFlags = flags; 441} 442 443SkLightingShaderImpl::LightingShaderContext::~LightingShaderContext() { 444 // The bitmap proc states have been created outside of the context on memory that will be freed 445 // elsewhere. Call the destructors but leave the freeing of the memory to the caller. 446 fDiffuseState->~SkBitmapProcState(); 447 fNormalState->~SkBitmapProcState(); 448} 449 450static inline SkPMColor convert(SkColor3f color, U8CPU a) { 451 if (color.fX <= 0.0f) { 452 color.fX = 0.0f; 453 } else if (color.fX >= 255.0f) { 454 color.fX = 255.0f; 455 } 456 457 if (color.fY <= 0.0f) { 458 color.fY = 0.0f; 459 } else if (color.fY >= 255.0f) { 460 color.fY = 255.0f; 461 } 462 463 if (color.fZ <= 0.0f) { 464 color.fZ = 0.0f; 465 } else if (color.fZ >= 255.0f) { 466 color.fZ = 255.0f; 467 } 468 469 return SkPreMultiplyARGB(a, (int) color.fX, (int) color.fY, (int) color.fZ); 470} 471 472// larger is better (fewer times we have to loop), but we shouldn't 473// take up too much stack-space (each one here costs 16 bytes) 474#define TMP_COUNT 16 475 476void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y, 477 SkPMColor result[], int count) { 478 const SkLightingShaderImpl& lightShader = static_cast<const SkLightingShaderImpl&>(fShader); 479 480 uint32_t tmpColor[TMP_COUNT], tmpNormal[TMP_COUNT]; 481 SkPMColor tmpColor2[2*TMP_COUNT], tmpNormal2[2*TMP_COUNT]; 482 483 SkBitmapProcState::MatrixProc diffMProc = fDiffuseState->getMatrixProc(); 484 SkBitmapProcState::SampleProc32 diffSProc = fDiffuseState->getSampleProc32(); 485 486 SkBitmapProcState::MatrixProc normalMProc = fNormalState->getMatrixProc(); 487 SkBitmapProcState::SampleProc32 normalSProc = fNormalState->getSampleProc32(); 488 489 int diffMax = fDiffuseState->maxCountForBufferSize(sizeof(tmpColor[0]) * TMP_COUNT); 490 int normMax = fNormalState->maxCountForBufferSize(sizeof(tmpNormal[0]) * TMP_COUNT); 491 int max = SkTMin(diffMax, normMax); 492 493 SkASSERT(fDiffuseState->fPixmap.addr()); 494 SkASSERT(fNormalState->fPixmap.addr()); 495 496 SkPoint3 norm, xformedNorm; 497 498 do { 499 int n = count; 500 if (n > max) { 501 n = max; 502 } 503 504 diffMProc(*fDiffuseState, tmpColor, n, x, y); 505 diffSProc(*fDiffuseState, tmpColor, n, tmpColor2); 506 507 normalMProc(*fNormalState, tmpNormal, n, x, y); 508 normalSProc(*fNormalState, tmpNormal, n, tmpNormal2); 509 510 for (int i = 0; i < n; ++i) { 511 SkASSERT(0xFF == SkColorGetA(tmpNormal2[i])); // opaque -> unpremul 512 norm.set(SkIntToScalar(SkGetPackedR32(tmpNormal2[i]))-127.0f, 513 SkIntToScalar(SkGetPackedG32(tmpNormal2[i]))-127.0f, 514 SkIntToScalar(SkGetPackedB32(tmpNormal2[i]))-127.0f); 515 norm.normalize(); 516 517 xformedNorm.fX = lightShader.fInvNormRotation.fX * norm.fX + 518 lightShader.fInvNormRotation.fY * norm.fY; 519 xformedNorm.fY = lightShader.fInvNormRotation.fX * norm.fX - 520 lightShader.fInvNormRotation.fY * norm.fY; 521 xformedNorm.fZ = norm.fZ; 522 523 SkColor diffColor = SkUnPreMultiply::PMColorToColor(tmpColor2[i]); 524 525 SkColor3f accum = SkColor3f::Make(0.0f, 0.0f, 0.0f); 526 // This is all done in linear unpremul color space (each component 0..255.0f though) 527 for (int l = 0; l < lightShader.fLights->numLights(); ++l) { 528 const SkLight& light = lightShader.fLights->light(l); 529 530 if (SkLight::kAmbient_LightType == light.type()) { 531 accum += light.color().makeScale(255.0f); 532 } else { 533 SkScalar NdotL = xformedNorm.dot(light.dir()); 534 if (NdotL < 0.0f) { 535 NdotL = 0.0f; 536 } 537 538 accum.fX += light.color().fX * SkColorGetR(diffColor) * NdotL; 539 accum.fY += light.color().fY * SkColorGetG(diffColor) * NdotL; 540 accum.fZ += light.color().fZ * SkColorGetB(diffColor) * NdotL; 541 } 542 } 543 544 result[i] = convert(accum, SkColorGetA(diffColor)); 545 } 546 547 result += n; 548 x += n; 549 count -= n; 550 } while (count > 0); 551} 552 553//////////////////////////////////////////////////////////////////////////// 554 555#ifndef SK_IGNORE_TO_STRING 556void SkLightingShaderImpl::toString(SkString* str) const { 557 str->appendf("LightingShader: ()"); 558} 559#endif 560 561SkFlattenable* SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) { 562 SkMatrix diffLocalM; 563 bool hasDiffLocalM = buf.readBool(); 564 if (hasDiffLocalM) { 565 buf.readMatrix(&diffLocalM); 566 } else { 567 diffLocalM.reset(); 568 } 569 570 SkMatrix normLocalM; 571 bool hasNormLocalM = buf.readBool(); 572 if (hasNormLocalM) { 573 buf.readMatrix(&normLocalM); 574 } else { 575 normLocalM.reset(); 576 } 577 578 SkBitmap diffuse; 579 if (!buf.readBitmap(&diffuse)) { 580 return nullptr; 581 } 582 diffuse.setImmutable(); 583 584 SkBitmap normal; 585 if (!buf.readBitmap(&normal)) { 586 return nullptr; 587 } 588 normal.setImmutable(); 589 590 int numLights = buf.readInt(); 591 592 SkLightingShader::Lights::Builder builder; 593 594 for (int l = 0; l < numLights; ++l) { 595 bool isAmbient = buf.readBool(); 596 597 SkColor3f color; 598 if (!buf.readScalarArray(&color.fX, 3)) { 599 return nullptr; 600 } 601 602 if (isAmbient) { 603 builder.add(SkLight(color)); 604 } else { 605 SkVector3 dir; 606 if (!buf.readScalarArray(&dir.fX, 3)) { 607 return nullptr; 608 } 609 builder.add(SkLight(color, dir)); 610 } 611 } 612 613 SkAutoTUnref<const SkLightingShader::Lights> lights(builder.finish()); 614 615 return new SkLightingShaderImpl(diffuse, normal, lights, SkVector::Make(1.0f, 0.0f), 616 &diffLocalM, &normLocalM); 617} 618 619void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const { 620 this->INHERITED::flatten(buf); 621 622 bool hasNormLocalM = !fNormLocalMatrix.isIdentity(); 623 buf.writeBool(hasNormLocalM); 624 if (hasNormLocalM) { 625 buf.writeMatrix(fNormLocalMatrix); 626 } 627 628 buf.writeBitmap(fDiffuseMap); 629 buf.writeBitmap(fNormalMap); 630 631 buf.writeInt(fLights->numLights()); 632 for (int l = 0; l < fLights->numLights(); ++l) { 633 const SkLight& light = fLights->light(l); 634 635 bool isAmbient = SkLight::kAmbient_LightType == light.type(); 636 637 buf.writeBool(isAmbient); 638 buf.writeScalarArray(&light.color().fX, 3); 639 if (!isAmbient) { 640 buf.writeScalarArray(&light.dir().fX, 3); 641 } 642 } 643} 644 645bool SkLightingShaderImpl::computeNormTotalInverse(const ContextRec& rec, 646 SkMatrix* normTotalInverse) const { 647 SkMatrix total; 648 total.setConcat(*rec.fMatrix, fNormLocalMatrix); 649 650 const SkMatrix* m = &total; 651 if (rec.fLocalMatrix) { 652 total.setConcat(*m, *rec.fLocalMatrix); 653 m = &total; 654 } 655 return m->invert(normTotalInverse); 656} 657 658SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec, 659 void* storage) const { 660 661 SkMatrix diffTotalInv; 662 // computeTotalInverse was called in SkShader::createContext so we know it will succeed 663 SkAssertResult(this->computeTotalInverse(rec, &diffTotalInv)); 664 665 SkMatrix normTotalInv; 666 if (!this->computeNormTotalInverse(rec, &normTotalInv)) { 667 return nullptr; 668 } 669 670 void* diffuseStateStorage = (char*)storage + sizeof(LightingShaderContext); 671 SkBitmapProcState* diffuseState = new (diffuseStateStorage) SkBitmapProcState(fDiffuseMap, 672 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); 673 SkASSERT(diffuseState); 674 if (!diffuseState->chooseProcs(diffTotalInv, *rec.fPaint)) { 675 diffuseState->~SkBitmapProcState(); 676 return nullptr; 677 } 678 679 void* normalStateStorage = (char*)storage + sizeof(LightingShaderContext) + sizeof(SkBitmapProcState); 680 SkBitmapProcState* normalState = new (normalStateStorage) SkBitmapProcState(fNormalMap, 681 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); 682 SkASSERT(normalState); 683 if (!normalState->chooseProcs(normTotalInv, *rec.fPaint)) { 684 diffuseState->~SkBitmapProcState(); 685 normalState->~SkBitmapProcState(); 686 return nullptr; 687 } 688 689 return new (storage) LightingShaderContext(*this, rec, diffuseState, normalState); 690} 691 692/////////////////////////////////////////////////////////////////////////////// 693 694static bool bitmap_is_too_big(const SkBitmap& bm) { 695 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it 696 // communicates between its matrix-proc and its sampler-proc. Until we can 697 // widen that, we have to reject bitmaps that are larger. 698 // 699 static const int kMaxSize = 65535; 700 701 return bm.width() > kMaxSize || bm.height() > kMaxSize; 702} 703 704SkShader* SkLightingShader::Create(const SkBitmap& diffuse, const SkBitmap& normal, 705 const Lights* lights, 706 const SkVector& invNormRotation, 707 const SkMatrix* diffLocalM, const SkMatrix* normLocalM) { 708 if (diffuse.isNull() || bitmap_is_too_big(diffuse) || 709 normal.isNull() || bitmap_is_too_big(normal) || 710 diffuse.width() != normal.width() || 711 diffuse.height() != normal.height()) { 712 return nullptr; 713 } 714 715 SkASSERT(SkScalarNearlyEqual(invNormRotation.lengthSqd(), SK_Scalar1)); 716 717 return new SkLightingShaderImpl(diffuse, normal, lights, invNormRotation, diffLocalM, 718 normLocalM); 719} 720 721/////////////////////////////////////////////////////////////////////////////// 722 723SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingShader) 724 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingShaderImpl) 725SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 726 727/////////////////////////////////////////////////////////////////////////////// 728