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 |