blob: b478ee7eca29f0f73ed4d918badc245d380309be [file] [log] [blame]
robertphillips2f0dbc72015-08-20 05:15:06 -07001/*
2 * Copyright 2015 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
dvonbeck8811e402016-06-16 12:39:25 -07008#include "SkBitmapProcShader.h"
robertphillips2f0dbc72015-08-20 05:15:06 -07009#include "SkBitmapProcState.h"
10#include "SkColor.h"
11#include "SkEmptyShader.h"
12#include "SkErrorInternals.h"
13#include "SkLightingShader.h"
14#include "SkMathPriv.h"
dvonbeck12c4fc22016-06-27 11:40:45 -070015#include "SkNormalSource.h"
robertphillips2f0dbc72015-08-20 05:15:06 -070016#include "SkPoint3.h"
17#include "SkReadBuffer.h"
18#include "SkWriteBuffer.h"
19
20////////////////////////////////////////////////////////////////////////////
21
22/*
23 SkLightingShader TODOs:
robertphillips2f0dbc72015-08-20 05:15:06 -070024 support different light types
25 support multiple lights
dvonbeckc526da92016-07-20 11:20:30 -070026 fix non-opaque diffuse textures
robertphillips2f0dbc72015-08-20 05:15:06 -070027
28 To Test:
robertphillips2f0dbc72015-08-20 05:15:06 -070029 A8 diffuse textures
30 down & upsampled draws
31*/
32
33
34
35/** \class SkLightingShaderImpl
36 This subclass of shader applies lighting.
37*/
dvonbeck8811e402016-06-16 12:39:25 -070038class SkLightingShaderImpl : public SkShader {
robertphillips2f0dbc72015-08-20 05:15:06 -070039public:
robertphillips2f0dbc72015-08-20 05:15:06 -070040 /** Create a new lighting shader that uses the provided normal map and
41 lights to light the diffuse bitmap.
dvonbecke6347ad2016-07-09 17:08:15 -070042 @param diffuseShader the shader that provides the diffuse colors
dvonbeck5b794fa2016-07-06 13:58:36 -070043 @param normalSource the source of normals for lighting computation
dvonbecke6347ad2016-07-09 17:08:15 -070044 @param lights the lights applied to the geometry
robertphillips2f0dbc72015-08-20 05:15:06 -070045 */
dvonbecke6347ad2016-07-09 17:08:15 -070046 SkLightingShaderImpl(sk_sp<SkShader> diffuseShader,
47 sk_sp<SkNormalSource> normalSource,
vjiaoblack95302da2016-07-21 10:25:54 -070048 sk_sp<SkLights> lights)
dvonbecke6347ad2016-07-09 17:08:15 -070049 : fDiffuseShader(std::move(diffuseShader))
50 , fNormalSource(std::move(normalSource))
51 , fLights(std::move(lights)) {}
robertphillips2f0dbc72015-08-20 05:15:06 -070052
53 bool isOpaque() const override;
54
bsalomonc21b09e2015-08-28 18:46:56 -070055#if SK_SUPPORT_GPU
brianosman839345d2016-07-22 11:04:53 -070056 sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
bsalomonc21b09e2015-08-28 18:46:56 -070057#endif
robertphillips2f0dbc72015-08-20 05:15:06 -070058
robertphillips2f0dbc72015-08-20 05:15:06 -070059 class LightingShaderContext : public SkShader::Context {
60 public:
61 // The context takes ownership of the states. It will call their destructors
62 // but will NOT free the memory.
63 LightingShaderContext(const SkLightingShaderImpl&, const ContextRec&,
dvonbecke6347ad2016-07-09 17:08:15 -070064 SkShader::Context* diffuseContext, SkNormalSource::Provider*,
dvonbeck12c4fc22016-06-27 11:40:45 -070065 void* heapAllocated);
dvonbecke6347ad2016-07-09 17:08:15 -070066
robertphillips2f0dbc72015-08-20 05:15:06 -070067 ~LightingShaderContext() override;
68
69 void shadeSpan(int x, int y, SkPMColor[], int count) override;
70
71 uint32_t getFlags() const override { return fFlags; }
72
73 private:
dvonbecke6347ad2016-07-09 17:08:15 -070074 SkShader::Context* fDiffuseContext;
dvonbeck12c4fc22016-06-27 11:40:45 -070075 SkNormalSource::Provider* fNormalProvider;
dvonbeckc526da92016-07-20 11:20:30 -070076 SkColor fPaintColor;
dvonbeck12c4fc22016-06-27 11:40:45 -070077 uint32_t fFlags;
78
79 void* fHeapAllocated;
robertphillips2f0dbc72015-08-20 05:15:06 -070080
81 typedef SkShader::Context INHERITED;
82 };
83
84 SK_TO_STRING_OVERRIDE()
85 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLightingShaderImpl)
86
87protected:
88 void flatten(SkWriteBuffer&) const override;
reed773ceda2016-03-03 18:18:25 -080089 size_t onContextSize(const ContextRec&) const override;
robertphillips2f0dbc72015-08-20 05:15:06 -070090 Context* onCreateContext(const ContextRec&, void*) const override;
robertphillips2f0dbc72015-08-20 05:15:06 -070091
92private:
dvonbecke6347ad2016-07-09 17:08:15 -070093 sk_sp<SkShader> fDiffuseShader;
rmistry0e569722016-07-08 06:23:35 -070094 sk_sp<SkNormalSource> fNormalSource;
dvonbecke6347ad2016-07-09 17:08:15 -070095 sk_sp<SkLights> fLights;
rmistry0e569722016-07-08 06:23:35 -070096
robertphillips2f0dbc72015-08-20 05:15:06 -070097 friend class SkLightingShader;
98
99 typedef SkShader INHERITED;
100};
101
102////////////////////////////////////////////////////////////////////////////
103
104#if SK_SUPPORT_GPU
105
106#include "GrCoordTransform.h"
107#include "GrFragmentProcessor.h"
egdaniel7ea439b2015-12-03 09:20:44 -0800108#include "GrInvariantOutput.h"
robertphillips2f0dbc72015-08-20 05:15:06 -0700109#include "GrTextureAccess.h"
egdaniel64c47282015-11-13 06:54:19 -0800110#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel2d721d32015-11-11 13:06:05 -0800111#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -0700112#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -0800113#include "glsl/GrGLSLUniformHandler.h"
robertphillips2f0dbc72015-08-20 05:15:06 -0700114#include "SkGr.h"
bsalomonf276ac52015-10-09 13:36:42 -0700115#include "SkGrPriv.h"
robertphillips2f0dbc72015-08-20 05:15:06 -0700116
dvonbeckc526da92016-07-20 11:20:30 -0700117// This FP expects a premul'd color input for its diffuse color. Premul'ing of the paint's color is
118// handled by the asFragmentProcessor() factory, but shaders providing diffuse color must output it
119// premul'd.
robertphillips2f0dbc72015-08-20 05:15:06 -0700120class LightingFP : public GrFragmentProcessor {
121public:
dvonbecke6347ad2016-07-09 17:08:15 -0700122 LightingFP(sk_sp<GrFragmentProcessor> normalFP, sk_sp<SkLights> lights) {
robertphillips2f0dbc72015-08-20 05:15:06 -0700123
124 // fuse all ambient lights into a single one
125 fAmbientColor.set(0.0f, 0.0f, 0.0f);
126 for (int i = 0; i < lights->numLights(); ++i) {
robertphillips71e05522016-05-31 12:08:25 -0700127 if (SkLights::Light::kAmbient_LightType == lights->light(i).type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -0700128 fAmbientColor += lights->light(i).color();
129 } else {
130 // TODO: handle more than one of these
131 fLightColor = lights->light(i).color();
132 fLightDir = lights->light(i).dir();
vjiaoblack95302da2016-07-21 10:25:54 -0700133 // TODO get the handle to the shadow map if there is one
robertphillips2f0dbc72015-08-20 05:15:06 -0700134 }
135 }
136
dvonbeck8811e402016-06-16 12:39:25 -0700137 this->registerChildProcessor(std::move(normalFP));
robertphillips2f0dbc72015-08-20 05:15:06 -0700138 this->initClassID<LightingFP>();
139 }
140
dvonbeck8811e402016-06-16 12:39:25 -0700141 class GLSLLightingFP : public GrGLSLFragmentProcessor {
robertphillips2f0dbc72015-08-20 05:15:06 -0700142 public:
dvonbeck8811e402016-06-16 12:39:25 -0700143 GLSLLightingFP() {
robertphillips2f0dbc72015-08-20 05:15:06 -0700144 fLightDir.fX = 10000.0f;
145 fLightColor.fX = 0.0f;
146 fAmbientColor.fX = 0.0f;
robertphillips2f0dbc72015-08-20 05:15:06 -0700147 }
148
149 void emitCode(EmitArgs& args) override {
150
egdaniel4ca2e602015-11-18 08:01:26 -0800151 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800152 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
robertphillips2f0dbc72015-08-20 05:15:06 -0700153
154 // add uniforms
halcanary96fcdcc2015-08-27 07:41:13 -0700155 const char* lightDirUniName = nullptr;
cdalton5e58cee2016-02-11 12:49:47 -0800156 fLightDirUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800157 kVec3f_GrSLType, kDefault_GrSLPrecision,
158 "LightDir", &lightDirUniName);
robertphillips2f0dbc72015-08-20 05:15:06 -0700159
halcanary96fcdcc2015-08-27 07:41:13 -0700160 const char* lightColorUniName = nullptr;
cdalton5e58cee2016-02-11 12:49:47 -0800161 fLightColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800162 kVec3f_GrSLType, kDefault_GrSLPrecision,
163 "LightColor", &lightColorUniName);
robertphillips2f0dbc72015-08-20 05:15:06 -0700164
halcanary96fcdcc2015-08-27 07:41:13 -0700165 const char* ambientColorUniName = nullptr;
cdalton5e58cee2016-02-11 12:49:47 -0800166 fAmbientColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800167 kVec3f_GrSLType, kDefault_GrSLPrecision,
168 "AmbientColor", &ambientColorUniName);
robertphillips2f0dbc72015-08-20 05:15:06 -0700169
dvonbecke6347ad2016-07-09 17:08:15 -0700170 fragBuilder->codeAppendf("vec4 diffuseColor = %s;", args.fInputColor);
robertphillips2f0dbc72015-08-20 05:15:06 -0700171
dvonbeck8811e402016-06-16 12:39:25 -0700172 SkString dstNormalName("dstNormal");
173 this->emitChild(0, nullptr, &dstNormalName, args);
robertphillips2f0dbc72015-08-20 05:15:06 -0700174
dvonbeck8811e402016-06-16 12:39:25 -0700175 fragBuilder->codeAppendf("vec3 normal = %s.xyz;", dstNormalName.c_str());
vjiaoblack95302da2016-07-21 10:25:54 -0700176
177 // TODO: make this a loop and modulate the contribution from each light
178 // based on the shadow map
egdaniel4ca2e602015-11-18 08:01:26 -0800179 fragBuilder->codeAppendf("float NdotL = clamp(dot(normal, %s), 0.0, 1.0);",
180 lightDirUniName);
robertphillips2f0dbc72015-08-20 05:15:06 -0700181 // diffuse light
egdaniel4ca2e602015-11-18 08:01:26 -0800182 fragBuilder->codeAppendf("vec3 result = %s*diffuseColor.rgb*NdotL;", lightColorUniName);
dvonbeckc526da92016-07-20 11:20:30 -0700183 // ambient light (multiplied by input color's alpha because we're working in premul'd
184 // space)
185 fragBuilder->codeAppendf("result += diffuseColor.a * %s;", ambientColorUniName);
186
187 // Clamping to alpha (equivalent to an unpremul'd clamp to 1.0)
188 fragBuilder->codeAppendf("%s = vec4(clamp(result.rgb, 0.0, diffuseColor.a), "
189 "diffuseColor.a);", args.fOutputColor);
robertphillips2f0dbc72015-08-20 05:15:06 -0700190 }
191
192 static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
193 GrProcessorKeyBuilder* b) {
194// const LightingFP& lightingFP = proc.cast<LightingFP>();
195 // only one shader generated currently
196 b->add32(0x0);
197 }
198
199 protected:
egdaniel018fb622015-10-28 07:26:40 -0700200 void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
robertphillips2f0dbc72015-08-20 05:15:06 -0700201 const LightingFP& lightingFP = proc.cast<LightingFP>();
202
203 const SkVector3& lightDir = lightingFP.lightDir();
204 if (lightDir != fLightDir) {
205 pdman.set3fv(fLightDirUni, 1, &lightDir.fX);
206 fLightDir = lightDir;
207 }
208
209 const SkColor3f& lightColor = lightingFP.lightColor();
210 if (lightColor != fLightColor) {
211 pdman.set3fv(fLightColorUni, 1, &lightColor.fX);
212 fLightColor = lightColor;
213 }
214
215 const SkColor3f& ambientColor = lightingFP.ambientColor();
216 if (ambientColor != fAmbientColor) {
217 pdman.set3fv(fAmbientColorUni, 1, &ambientColor.fX);
218 fAmbientColor = ambientColor;
219 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700220 }
221
222 private:
223 SkVector3 fLightDir;
egdaniel018fb622015-10-28 07:26:40 -0700224 GrGLSLProgramDataManager::UniformHandle fLightDirUni;
robertphillips2f0dbc72015-08-20 05:15:06 -0700225
226 SkColor3f fLightColor;
egdaniel018fb622015-10-28 07:26:40 -0700227 GrGLSLProgramDataManager::UniformHandle fLightColorUni;
robertphillips2f0dbc72015-08-20 05:15:06 -0700228
229 SkColor3f fAmbientColor;
egdaniel018fb622015-10-28 07:26:40 -0700230 GrGLSLProgramDataManager::UniformHandle fAmbientColorUni;
robertphillips2f0dbc72015-08-20 05:15:06 -0700231 };
232
egdaniel57d3b032015-11-13 11:57:27 -0800233 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
dvonbeck8811e402016-06-16 12:39:25 -0700234 GLSLLightingFP::GenKey(*this, caps, b);
robertphillips2f0dbc72015-08-20 05:15:06 -0700235 }
236
237 const char* name() const override { return "LightingFP"; }
238
239 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
240 inout->mulByUnknownFourComponents();
241 }
242
243 const SkVector3& lightDir() const { return fLightDir; }
244 const SkColor3f& lightColor() const { return fLightColor; }
245 const SkColor3f& ambientColor() const { return fAmbientColor; }
robertphillips2f0dbc72015-08-20 05:15:06 -0700246
247private:
dvonbeck8811e402016-06-16 12:39:25 -0700248 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLLightingFP; }
robertphillips2f0dbc72015-08-20 05:15:06 -0700249
halcanary9d524f22016-03-29 09:03:52 -0700250 bool onIsEqual(const GrFragmentProcessor& proc) const override {
robertphillips2f0dbc72015-08-20 05:15:06 -0700251 const LightingFP& lightingFP = proc.cast<LightingFP>();
dvonbecke6347ad2016-07-09 17:08:15 -0700252 return fLightDir == lightingFP.fLightDir &&
robertphillips2f0dbc72015-08-20 05:15:06 -0700253 fLightColor == lightingFP.fLightColor &&
dvonbeck8811e402016-06-16 12:39:25 -0700254 fAmbientColor == lightingFP.fAmbientColor;
robertphillips2f0dbc72015-08-20 05:15:06 -0700255 }
256
robertphillips2f0dbc72015-08-20 05:15:06 -0700257 SkVector3 fLightDir;
258 SkColor3f fLightColor;
259 SkColor3f fAmbientColor;
robertphillips2f0dbc72015-08-20 05:15:06 -0700260};
261
262////////////////////////////////////////////////////////////////////////////
263
brianosman839345d2016-07-22 11:04:53 -0700264sk_sp<GrFragmentProcessor> SkLightingShaderImpl::asFragmentProcessor(const AsFPArgs& args) const {
265 sk_sp<GrFragmentProcessor> normalFP(fNormalSource->asFragmentProcessor(args));
dvonbecke6347ad2016-07-09 17:08:15 -0700266 if (!normalFP) {
267 return nullptr;
268 }
269
dvonbeckc526da92016-07-20 11:20:30 -0700270 if (fDiffuseShader) {
271 sk_sp<GrFragmentProcessor> fpPipeline[] = {
brianosman839345d2016-07-22 11:04:53 -0700272 fDiffuseShader->asFragmentProcessor(args),
dvonbecke6347ad2016-07-09 17:08:15 -0700273 sk_make_sp<LightingFP>(std::move(normalFP), fLights)
dvonbeckc526da92016-07-20 11:20:30 -0700274 };
275 if(!fpPipeline[0]) {
276 return nullptr;
277 }
278
279 sk_sp<GrFragmentProcessor> innerLightFP = GrFragmentProcessor::RunInSeries(fpPipeline, 2);
280 // FP is wrapped because paint's alpha needs to be applied to output
281 return GrFragmentProcessor::MulOutputByInputAlpha(std::move(innerLightFP));
282 } else {
283 // FP is wrapped because paint comes in unpremul'd to fragment shader, but LightingFP
284 // expects premul'd color.
285 return GrFragmentProcessor::PremulInput(sk_make_sp<LightingFP>(std::move(normalFP),
286 fLights));
dvonbecke6347ad2016-07-09 17:08:15 -0700287 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700288}
289
290#endif
291
292////////////////////////////////////////////////////////////////////////////
293
294bool SkLightingShaderImpl::isOpaque() const {
dvonbeckc526da92016-07-20 11:20:30 -0700295 return (fDiffuseShader ? fDiffuseShader->isOpaque() : false);
robertphillips2f0dbc72015-08-20 05:15:06 -0700296}
297
dvonbeck8811e402016-06-16 12:39:25 -0700298SkLightingShaderImpl::LightingShaderContext::LightingShaderContext(
dvonbecke6347ad2016-07-09 17:08:15 -0700299 const SkLightingShaderImpl& shader, const ContextRec& rec,
300 SkShader::Context* diffuseContext, SkNormalSource::Provider* normalProvider,
301 void* heapAllocated)
robertphillips2f0dbc72015-08-20 05:15:06 -0700302 : INHERITED(shader, rec)
dvonbecke6347ad2016-07-09 17:08:15 -0700303 , fDiffuseContext(diffuseContext)
dvonbeck12c4fc22016-06-27 11:40:45 -0700304 , fNormalProvider(normalProvider)
305 , fHeapAllocated(heapAllocated) {
dvonbecke6347ad2016-07-09 17:08:15 -0700306 bool isOpaque = shader.isOpaque();
robertphillips2f0dbc72015-08-20 05:15:06 -0700307
308 // update fFlags
309 uint32_t flags = 0;
310 if (isOpaque && (255 == this->getPaintAlpha())) {
311 flags |= kOpaqueAlpha_Flag;
312 }
313
dvonbeckc526da92016-07-20 11:20:30 -0700314 fPaintColor = rec.fPaint->getColor();
robertphillips2f0dbc72015-08-20 05:15:06 -0700315 fFlags = flags;
316}
317
318SkLightingShaderImpl::LightingShaderContext::~LightingShaderContext() {
dvonbecke6347ad2016-07-09 17:08:15 -0700319 // The dependencies have been created outside of the context on memory that was allocated by
320 // the onCreateContext() method. Call the destructors and free the memory.
dvonbeckc526da92016-07-20 11:20:30 -0700321 if (fDiffuseContext) {
322 fDiffuseContext->~Context();
323 }
dvonbeck12c4fc22016-06-27 11:40:45 -0700324 fNormalProvider->~Provider();
325
326 sk_free(fHeapAllocated);
robertphillips2f0dbc72015-08-20 05:15:06 -0700327}
328
329static inline SkPMColor convert(SkColor3f color, U8CPU a) {
330 if (color.fX <= 0.0f) {
331 color.fX = 0.0f;
332 } else if (color.fX >= 255.0f) {
333 color.fX = 255.0f;
halcanary9d524f22016-03-29 09:03:52 -0700334 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700335
336 if (color.fY <= 0.0f) {
337 color.fY = 0.0f;
338 } else if (color.fY >= 255.0f) {
339 color.fY = 255.0f;
halcanary9d524f22016-03-29 09:03:52 -0700340 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700341
342 if (color.fZ <= 0.0f) {
343 color.fZ = 0.0f;
344 } else if (color.fZ >= 255.0f) {
345 color.fZ = 255.0f;
halcanary9d524f22016-03-29 09:03:52 -0700346 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700347
348 return SkPreMultiplyARGB(a, (int) color.fX, (int) color.fY, (int) color.fZ);
349}
350
351// larger is better (fewer times we have to loop), but we shouldn't
352// take up too much stack-space (each one here costs 16 bytes)
dvonbecke6347ad2016-07-09 17:08:15 -0700353#define BUFFER_MAX 16
robertphillips2f0dbc72015-08-20 05:15:06 -0700354void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y,
355 SkPMColor result[], int count) {
356 const SkLightingShaderImpl& lightShader = static_cast<const SkLightingShaderImpl&>(fShader);
357
dvonbecke6347ad2016-07-09 17:08:15 -0700358 SkPMColor diffuse[BUFFER_MAX];
dvonbeck12c4fc22016-06-27 11:40:45 -0700359 SkPoint3 normals[BUFFER_MAX];
robertphillips2f0dbc72015-08-20 05:15:06 -0700360
dvonbeckc526da92016-07-20 11:20:30 -0700361 SkColor diffColor = fPaintColor;
362
robertphillips2f0dbc72015-08-20 05:15:06 -0700363 do {
dvonbecke6347ad2016-07-09 17:08:15 -0700364 int n = SkTMin(count, BUFFER_MAX);
robertphillips2f0dbc72015-08-20 05:15:06 -0700365
dvonbeck12c4fc22016-06-27 11:40:45 -0700366 fNormalProvider->fillScanLine(x, y, normals, n);
robertphillips2f0dbc72015-08-20 05:15:06 -0700367
dvonbeckc526da92016-07-20 11:20:30 -0700368 if (fDiffuseContext) {
369 fDiffuseContext->shadeSpan(x, y, diffuse, n);
370 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700371
dvonbeckc526da92016-07-20 11:20:30 -0700372 for (int i = 0; i < n; ++i) {
373 if (fDiffuseContext) {
374 diffColor = SkUnPreMultiply::PMColorToColor(diffuse[i]);
375 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700376
377 SkColor3f accum = SkColor3f::Make(0.0f, 0.0f, 0.0f);
378 // This is all done in linear unpremul color space (each component 0..255.0f though)
379 for (int l = 0; l < lightShader.fLights->numLights(); ++l) {
robertphillips71e05522016-05-31 12:08:25 -0700380 const SkLights::Light& light = lightShader.fLights->light(l);
robertphillips2f0dbc72015-08-20 05:15:06 -0700381
robertphillips71e05522016-05-31 12:08:25 -0700382 if (SkLights::Light::kAmbient_LightType == light.type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -0700383 accum += light.color().makeScale(255.0f);
384 } else {
dvonbeck12c4fc22016-06-27 11:40:45 -0700385 SkScalar NdotL = normals[i].dot(light.dir());
robertphillips2f0dbc72015-08-20 05:15:06 -0700386 if (NdotL < 0.0f) {
387 NdotL = 0.0f;
388 }
389
390 accum.fX += light.color().fX * SkColorGetR(diffColor) * NdotL;
391 accum.fY += light.color().fY * SkColorGetG(diffColor) * NdotL;
392 accum.fZ += light.color().fZ * SkColorGetB(diffColor) * NdotL;
393 }
394 }
395
dvonbeckc526da92016-07-20 11:20:30 -0700396 // convert() premultiplies the accumulate color with alpha
robertphillips2f0dbc72015-08-20 05:15:06 -0700397 result[i] = convert(accum, SkColorGetA(diffColor));
398 }
399
400 result += n;
401 x += n;
402 count -= n;
403 } while (count > 0);
404}
405
406////////////////////////////////////////////////////////////////////////////
407
408#ifndef SK_IGNORE_TO_STRING
409void SkLightingShaderImpl::toString(SkString* str) const {
410 str->appendf("LightingShader: ()");
411}
412#endif
413
reed60c9b582016-04-03 09:11:13 -0700414sk_sp<SkFlattenable> SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) {
robertphillips2f0dbc72015-08-20 05:15:06 -0700415
dvonbecke6347ad2016-07-09 17:08:15 -0700416 // Discarding SkShader flattenable params
417 bool hasLocalMatrix = buf.readBool();
418 SkAssertResult(!hasLocalMatrix);
robertphillips2f0dbc72015-08-20 05:15:06 -0700419
robertphillips2f0dbc72015-08-20 05:15:06 -0700420 int numLights = buf.readInt();
421
robertphillips71e05522016-05-31 12:08:25 -0700422 SkLights::Builder builder;
robertphillips2f0dbc72015-08-20 05:15:06 -0700423
424 for (int l = 0; l < numLights; ++l) {
425 bool isAmbient = buf.readBool();
426
427 SkColor3f color;
428 if (!buf.readScalarArray(&color.fX, 3)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700429 return nullptr;
robertphillips2f0dbc72015-08-20 05:15:06 -0700430 }
431
432 if (isAmbient) {
robertphillips71e05522016-05-31 12:08:25 -0700433 builder.add(SkLights::Light(color));
robertphillips2f0dbc72015-08-20 05:15:06 -0700434 } else {
435 SkVector3 dir;
436 if (!buf.readScalarArray(&dir.fX, 3)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700437 return nullptr;
robertphillips2f0dbc72015-08-20 05:15:06 -0700438 }
robertphillips71e05522016-05-31 12:08:25 -0700439 builder.add(SkLights::Light(color, dir));
robertphillips2f0dbc72015-08-20 05:15:06 -0700440 }
441 }
442
robertphillips71e05522016-05-31 12:08:25 -0700443 sk_sp<SkLights> lights(builder.finish());
robertphillips2f0dbc72015-08-20 05:15:06 -0700444
dvonbeck12c4fc22016-06-27 11:40:45 -0700445 sk_sp<SkNormalSource> normalSource(buf.readFlattenable<SkNormalSource>());
dvonbeckc526da92016-07-20 11:20:30 -0700446
447 bool hasDiffuse = buf.readBool();
448 sk_sp<SkShader> diffuseShader = nullptr;
449 if (hasDiffuse) {
450 diffuseShader = buf.readFlattenable<SkShader>();
451 }
dvonbeck8811e402016-06-16 12:39:25 -0700452
dvonbecke6347ad2016-07-09 17:08:15 -0700453 return sk_make_sp<SkLightingShaderImpl>(std::move(diffuseShader), std::move(normalSource),
454 std::move(lights));
robertphillips2f0dbc72015-08-20 05:15:06 -0700455}
456
457void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const {
458 this->INHERITED::flatten(buf);
459
robertphillips2f0dbc72015-08-20 05:15:06 -0700460 buf.writeInt(fLights->numLights());
461 for (int l = 0; l < fLights->numLights(); ++l) {
robertphillips71e05522016-05-31 12:08:25 -0700462 const SkLights::Light& light = fLights->light(l);
robertphillips2f0dbc72015-08-20 05:15:06 -0700463
robertphillips71e05522016-05-31 12:08:25 -0700464 bool isAmbient = SkLights::Light::kAmbient_LightType == light.type();
robertphillips2f0dbc72015-08-20 05:15:06 -0700465
466 buf.writeBool(isAmbient);
467 buf.writeScalarArray(&light.color().fX, 3);
468 if (!isAmbient) {
469 buf.writeScalarArray(&light.dir().fX, 3);
470 }
471 }
dvonbeck8811e402016-06-16 12:39:25 -0700472
473 buf.writeFlattenable(fNormalSource.get());
dvonbeckc526da92016-07-20 11:20:30 -0700474 buf.writeBool(fDiffuseShader);
475 if (fDiffuseShader) {
476 buf.writeFlattenable(fDiffuseShader.get());
477 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700478}
479
dvonbeck12c4fc22016-06-27 11:40:45 -0700480size_t SkLightingShaderImpl::onContextSize(const ContextRec& rec) const {
481 return sizeof(LightingShaderContext);
reed773ceda2016-03-03 18:18:25 -0800482}
483
robertphillips2f0dbc72015-08-20 05:15:06 -0700484SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec,
485 void* storage) const {
dvonbeckc526da92016-07-20 11:20:30 -0700486 size_t heapRequired = (fDiffuseShader ? fDiffuseShader->contextSize(rec) : 0) +
dvonbecke6347ad2016-07-09 17:08:15 -0700487 fNormalSource->providerSize(rec);
dvonbeck12c4fc22016-06-27 11:40:45 -0700488 void* heapAllocated = sk_malloc_throw(heapRequired);
dvonbeck2c807112016-06-27 09:30:19 -0700489
dvonbecke6347ad2016-07-09 17:08:15 -0700490 void* diffuseContextStorage = heapAllocated;
dvonbeckc526da92016-07-20 11:20:30 -0700491 void* normalProviderStorage = (char*) diffuseContextStorage +
492 (fDiffuseShader ? fDiffuseShader->contextSize(rec) : 0);
493
494 SkShader::Context *diffuseContext = nullptr;
495 if (fDiffuseShader) {
496 diffuseContext = fDiffuseShader->createContext(rec, diffuseContextStorage);
497 if (!diffuseContext) {
498 sk_free(heapAllocated);
499 return nullptr;
500 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700501 }
502
dvonbeck12c4fc22016-06-27 11:40:45 -0700503 SkNormalSource::Provider* normalProvider = fNormalSource->asProvider(rec,
504 normalProviderStorage);
505 if (!normalProvider) {
dvonbecke6347ad2016-07-09 17:08:15 -0700506 diffuseContext->~Context();
dvonbeck12c4fc22016-06-27 11:40:45 -0700507 sk_free(heapAllocated);
halcanary96fcdcc2015-08-27 07:41:13 -0700508 return nullptr;
robertphillips2f0dbc72015-08-20 05:15:06 -0700509 }
510
dvonbecke6347ad2016-07-09 17:08:15 -0700511 return new (storage) LightingShaderContext(*this, rec, diffuseContext, normalProvider,
dvonbeck12c4fc22016-06-27 11:40:45 -0700512 heapAllocated);
robertphillips2f0dbc72015-08-20 05:15:06 -0700513}
514
515///////////////////////////////////////////////////////////////////////////////
516
dvonbeck6af677f2016-07-10 18:38:33 -0700517sk_sp<SkShader> SkLightingShader::Make(sk_sp<SkShader> diffuseShader,
518 sk_sp<SkNormalSource> normalSource,
519 sk_sp<SkLights> lights) {
dvonbeckc526da92016-07-20 11:20:30 -0700520 if (!normalSource) {
521 normalSource = SkNormalSource::MakeFlat();
dvonbeck5b794fa2016-07-06 13:58:36 -0700522 }
dvonbeck12c4fc22016-06-27 11:40:45 -0700523
dvonbecke6347ad2016-07-09 17:08:15 -0700524 return sk_make_sp<SkLightingShaderImpl>(std::move(diffuseShader), std::move(normalSource),
525 std::move(lights));
robertphillips2f0dbc72015-08-20 05:15:06 -0700526}
527
528///////////////////////////////////////////////////////////////////////////////
529
530SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingShader)
531 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingShaderImpl)
532SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
533
534///////////////////////////////////////////////////////////////////////////////