Chromium Code Reviews| Index: include/effects/SkLightingShader.h |
| diff --git a/include/effects/SkLightingShader.h b/include/effects/SkLightingShader.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..7934345b7ef43c55bb473411c2a1d7af496ed760 |
| --- /dev/null |
| +++ b/include/effects/SkLightingShader.h |
| @@ -0,0 +1,134 @@ |
| + |
| +/* |
| + * Copyright 2015 Google Inc. |
| + * |
| + * Use of this source code is governed by a BSD-style license that can be |
| + * found in the LICENSE file. |
| + */ |
| + |
| + |
| +#ifndef SkLightingShader_DEFINED |
| +#define SkLightingShader_DEFINED |
| + |
| +#include "SkPoint3.h" |
| +#include "SkShader.h" |
| + |
| +/////////////////////////////////////////////////////////////////////////////////////////// |
| + |
| +/* |
| + SkLightingShader TODOs: |
| + support other than clamp mode |
| + allow 'diffuse' & 'normal' to be of different dimensions? |
| + support different light types |
| + support multiple lights |
| + enforce normal map is 4 channel |
|
jvanverth1
2015/07/23 17:40:14
use SkImages instead of SkBitmaps
robertphillips
2015/07/28 14:15:45
Done.
|
| + |
| + To Test: |
| + non-opaque diffuse textures |
| + A8 diffuse textures |
| + down & upsampled draws |
| +*/ |
| + |
| + |
| + |
| +/** \class SkLightingShader |
| + This subclass of shader applies lighting. |
| +*/ |
| +class SK_API SkLightingShader : public SkShader { |
| +public: |
| + struct Light { |
| + SkVector3 fDirection; // direction towards the light (+Z is out of the screen) |
| + SkColor fColor; // linear (unpremul) color |
| + }; |
| + |
| + /** Create a new lighting shader that use the provided normal map, light |
| + and ambient color to light the diffuse bitmap. |
| + @param diffuse the diffuse bitmap |
| + @param normal the normal map |
| + @param light the light applied to the normal map |
| + @param ambient the linear (unpremul) ambient light color |
| + */ |
| + SkLightingShader(const SkBitmap& diffuse, const SkBitmap& normal, const Light& light, |
| + const SkColor ambient) |
| + : fDiffuseMap(diffuse) |
| + , fNormalMap(normal) |
| + , fLight(light) |
| + , fAmbientColor(ambient) { |
| + if (!fLight.fDirection.normalize()) { |
| + fLight.fDirection = SkPoint3::Make(0.0f, 0.0f, 1.0f); |
| + } |
| + SkColorSetA(fLight.fColor, 0xFF); |
| + SkColorSetA(fAmbientColor, 0xFF); |
| + } |
| + |
| + bool isOpaque() const override; |
| + |
| + void setLight(const Light& light) { |
| + fLight = light; |
| + if (!fLight.fDirection.normalize()) { |
| + fLight.fDirection = SkPoint3::Make(0.0f, 0.0f, 1.0f); |
| + } |
| + SkColorSetA(fLight.fColor, 0xFF); |
| + SkColorSetA(fAmbientColor, 0xFF); |
| + } |
| + |
| + bool asFragmentProcessor(GrContext*, const SkPaint& paint, const SkMatrix& viewM, |
| + const SkMatrix* localMatrix, GrColor* color, |
| + GrProcessorDataManager*, GrFragmentProcessor** fp) const override; |
| + |
| + size_t contextSize() const override; |
| + |
| + class LightingShaderContext : public SkShader::Context { |
| + public: |
| + // The context takes ownership of the states. It will call their destructors |
| + // but will NOT free the memory. |
| + LightingShaderContext(const SkLightingShader&, const ContextRec&, |
| + SkBitmapProcState* diffuseState, SkBitmapProcState* normalState); |
| + ~LightingShaderContext() override; |
| + |
| + void shadeSpan(int x, int y, SkPMColor[], int count) override; |
| + |
| + uint32_t getFlags() const override { return fFlags; } |
| + |
| + private: |
| + SkBitmapProcState* fDiffuseState; |
| + SkBitmapProcState* fNormalState; |
| + uint32_t fFlags; |
| + |
| + typedef SkShader::Context INHERITED; |
| + }; |
| + |
| + SK_TO_STRING_OVERRIDE() |
| + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(LightingShader) |
| + |
| +protected: |
| + void flatten(SkWriteBuffer&) const override; |
| + Context* onCreateContext(const ContextRec&, void*) const override; |
| + |
| +private: |
| + SkBitmap fDiffuseMap; |
| + SkBitmap fNormalMap; |
| + Light fLight; |
| + SkColor fAmbientColor; // linear (unpremul) color |
| + |
| + typedef SkShader INHERITED; |
| +}; |
| + |
| +// TODO: it would be nice to be able to call this from SkShader but this |
| +// would need to reside in core. |
| +#if 0 |
| +// Commonly used allocator. It currently is only used to allocate up to 3 objects. The total |
| +// bytes requested is calculated using one of our large shaders, its context size plus the size of |
| +// an Sk3DBlitter in SkDraw.cpp |
| +// Note that some contexts may contain other contexts (e.g. for compose shaders), but we've not |
| +// yet found a situation where the size below isn't big enough. |
| +typedef SkSmallAllocator<3, 1024> SkTBlitterAllocator; |
| + |
| +// If alloc is non-NULL, it will be used to allocate the returned SkShader, and MUST outlive |
| +// the SkShader. |
| +SkShader* SkCreateLightingShader(const SkBitmap& diffuse, const SkBitmap& normal, |
| + const SkLightingShader::Light& light, const SkColor ambient, |
| + SkTBlitterAllocator* alloc); |
| +#endif |
| + |
| +#endif |