Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: samplecode/SampleLighting.cpp

Issue 1212813009: Add normal map sample (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Add uniform support for lighting values Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « resources/brickwork_normal-map.jpg ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 #include "SampleCode.h"
9 #include "Resources.h"
10
11 #include "SkCanvas.h"
12 #include "SkErrorInternals.h"
13 #include "SkGr.h"
14 #include "SkReadBuffer.h"
15 #include "SkShader.h"
16 #include "SkWriteBuffer.h"
17
18 #include "GrFragmentProcessor.h"
19 #include "GrCoordTransform.h"
20 #include "gl/GrGLProcessor.h"
21 #include "gl/builders/GrGLProgramBuilder.h"
22
23 ///////////////////////////////////////////////////////////////////////////////
24
25 struct SkVector3 {
26 SkScalar x, y, z;
27
28 bool operator!=(const SkVector3& other) {
29 return x != other.x || y != other.y || z != other.z;
30 }
31 };
32
33 class LightingShader : public SkShader {
34 public:
35 struct Light {
36 SkVector3 fDirection;
37 SkColor fColor; // assumed to be linear color
38 };
39
40 LightingShader(const SkBitmap& diffuse, const SkBitmap& normal, const Light& light,
41 const SkColor ambient)
42 : fDiffuseMap(diffuse)
43 , fNormalMap(normal)
44 , fLight(light)
45 , fAmbientColor(ambient) {}
46
47 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(LightingShader);
48
49 void flatten(SkWriteBuffer& buf) const override {
50 // buf.writeMatrix(fDeviceMatrix);
51 }
52
53 bool asFragmentProcessor(GrContext*, const SkPaint& paint, const SkMatrix& v iewM,
54 const SkMatrix* localMatrix, GrColor* color,
55 GrFragmentProcessor** fp) const override;
56
57 #ifndef SK_IGNORE_TO_STRING
58 void toString(SkString* str) const override {
59 str->appendf("LightingShader: ()");
60 }
61 #endif
62
63 void setLight(const Light& light) { fLight = light; }
64
65 private:
66 SkBitmap fDiffuseMap;
67 SkBitmap fNormalMap;
68 Light fLight;
69 SkColor fAmbientColor;
70 };
71
72 SkFlattenable* LightingShader::CreateProc(SkReadBuffer& buf) {
73 //SkMatrix matrix;
74 //buf.readMatrix(&matrix);
75 //return SkNEW_ARGS(LightingShader, (matrix));
76
77 return NULL;
78 }
79
80 ////////////////////////////////////////////////////////////////////////////
81
82 class LightingFP : public GrFragmentProcessor {
83 public:
84 LightingFP(GrTexture* diffuse, GrTexture* normal, const SkMatrix& matrix,
85 SkVector3 lightDir, GrColor lightColor, GrColor ambientColor)
86 : fDiffuseTextureAccess(diffuse)
87 , fNormalTextureAccess(normal)
88 , fDeviceTransform(kDevice_GrCoordSet, matrix)
89 , fLightDir(lightDir)
90 , fLightColor(lightColor)
91 , fAmbientColor(ambientColor) {
92 this->addCoordTransform(&fDeviceTransform);
93 this->addTextureAccess(&fDiffuseTextureAccess);
94 this->addTextureAccess(&fNormalTextureAccess);
95
96 this->initClassID<LightingFP>();
97 }
98
robertphillips 2015/07/08 16:15:14 one line ? Is this right ?
jvanverth1 2015/07/08 19:58:06 I think it's okay, but added the full GenKey() cod
99 void getGLProcessorKey(const GrGLSLCaps& caps,
100 GrProcessorKeyBuilder* b) const override {}
101
102 GrGLFragmentProcessor* createGLInstance() const override {
103 class LightingGLFP : public GrGLFragmentProcessor {
104 public:
105 LightingGLFP()
106 : fLightColor(GrColor_ILLEGAL) {
107 fLightDir.x = 10000.0f;
108 }
109
110 void emitCode(GrGLFPBuilder* builder,
robertphillips 2015/07/08 16:15:14 tab these over ?
jvanverth1 2015/07/08 19:58:06 Done.
111 const GrFragmentProcessor& fp,
112 const char* outputColor,
113 const char* inputColor,
114 const TransformedCoordsArray& coords,
robertphillips 2015/07/08 16:15:14 override ?
jvanverth1 2015/07/08 19:58:06 Done.
115 const TextureSamplerArray& samplers) {
116
117 GrGLFragmentBuilder* fpb = builder->getFragmentShaderBuilder();
118
119 // add uniforms
120 const char* lightDirUniName = NULL;
121 fLightDirUni = builder->addUniform(GrGLProgramBuilder::kFragment _Visibility,
122 kVec3f_GrSLType, kDefault_GrSLPrecision,
123 "LightDir", &lightDirUniName);
124
125 const char* lightColorUniName = NULL;
126 fLightColorUni = builder->addUniform(GrGLProgramBuilder::kFragme nt_Visibility,
127 kVec4f_GrSLType, kDefault_GrSLPrecision,
128 "LightColor", &lightColorUniName);
129
130 const char* ambientColorUniName = NULL;
131 fAmbientColorUni = builder->addUniform(GrGLProgramBuilder::kFrag ment_Visibility,
robertphillips 2015/07/08 16:15:14 tabs ?
jvanverth1 2015/07/08 19:58:06 Done.
132 kVec4f_GrSLType, kDefault_GrSLPrecision,
133 "AmbientColor", &ambientColorUniName);
134
135 fpb->codeAppend("vec4 diffuseColor = ");
136 fpb->appendTextureLookupAndModulate(inputColor,
robertphillips 2015/07/08 16:15:14 tabs ?
jvanverth1 2015/07/08 19:58:06 Done.
137 samplers[0],
138 coords[0].c_str(),
139 coords[0].getType());
140 fpb->codeAppend(";");
141
142 fpb->codeAppend("vec4 normalColor = ");
143 fpb->appendTextureLookup(samplers[1],
144 coords[0].c_str(),
145 coords[0].getType());
146 fpb->codeAppend(";");
147
148 fpb->codeAppend("vec3 normal = normalize(2.0*(normalColor.rgb - vec3(0.5)));");
149 fpb->codeAppendf("vec3 lightDir = normalize(%s);", lightDirUniNa me);
150 fpb->codeAppend("float NdotL = dot(normal, lightDir);");
151 // diffuse light
152 fpb->codeAppendf("vec3 result = %s.rgb*diffuseColor.rgb*NdotL;", lightColorUniName);
153 // ambient light
154 fpb->codeAppendf("result += %s.rgb;", ambientColorUniName);
155 fpb->codeAppendf("%s = vec4(result.rgb, diffuseColor.a);", outpu tColor);
156 }
157
158 void setData(const GrGLProgramDataManager& pdman, const GrProcessor& proc) override {
159 const LightingFP& lightingFP = proc.cast<LightingFP>();
160
161 SkVector3 lightDir = lightingFP.lightDir();
162 if (lightDir != fLightDir) {
163 pdman.set3fv(fLightDirUni, 1, &lightDir.x);
164 fLightDir = lightDir;
165 }
166
167 GrColor lightColor = lightingFP.lightColor();
168 if (lightColor != fLightColor) {
169 GrGLfloat c[4];
170 GrColorToRGBAFloat(lightColor, c);
171 pdman.set4fv(fLightColorUni, 1, c);
172 fLightColor = lightColor;
173 }
174
175 GrColor ambientColor = lightingFP.ambientColor();
176 if (ambientColor != fAmbientColor) {
177 GrGLfloat c[4];
178 GrColorToRGBAFloat(ambientColor, c);
179 pdman.set4fv(fAmbientColorUni, 1, c);
180 fAmbientColor = ambientColor;
181 }
182 }
183 private:
184 SkVector3 fLightDir;
185 GrGLProgramDataManager::UniformHandle fLightDirUni;
186
187 GrColor fLightColor;
188 GrGLProgramDataManager::UniformHandle fLightColorUni;
189
190 GrColor fAmbientColor;
191 GrGLProgramDataManager::UniformHandle fAmbientColorUni;
192 };
193 return SkNEW(LightingGLFP);
194 }
195
196 const char* name() const override { return "LightingGLFP"; }
197
198 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
199 inout->mulByUnknownFourComponents();
200 }
201
202 SkVector3 lightDir() const { return fLightDir; }
203 GrColor lightColor() const { return fLightColor; }
204 GrColor ambientColor() const { return fAmbientColor; }
205
206 private:
robertphillips 2015/07/08 16:15:14 ??
jvanverth1 2015/07/08 19:58:06 Done.
207 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
208
209 GrCoordTransform fDeviceTransform;
210 GrTextureAccess fDiffuseTextureAccess;
211 GrTextureAccess fNormalTextureAccess;
212 SkVector3 fLightDir;
213 GrColor fLightColor;
214 GrColor fAmbientColor;
215 };
216
217 bool LightingShader::asFragmentProcessor(GrContext* context, const SkPaint& pain t,
218 const SkMatrix& viewM, const SkMatrix* localMatrix,
219 GrColor* color, GrFragmentProcessor** f p) const {
220 // we assume diffuse and normal maps have same width and height
221 // TODO: support different sizes
222 SkASSERT(fDiffuseMap.width() == fNormalMap.width() &&
223 fDiffuseMap.height() == fNormalMap.height());
224 SkMatrix matrix;
225 matrix.setIDiv(fDiffuseMap.width(), fDiffuseMap.height());
226
227 SkMatrix lmInverse;
228 if (!this->getLocalMatrix().invert(&lmInverse)) {
229 return false;
230 }
231 if (localMatrix) {
232 SkMatrix inv;
233 if (!localMatrix->invert(&inv)) {
234 return false;
235 }
236 lmInverse.postConcat(inv);
237 }
238 matrix.preConcat(lmInverse);
239
240 // Must set wrap and filter on the sampler before requesting a texture. In t wo places below
241 // we check the matrix scale factors to determine how to interpret the filte r quality setting.
242 // This completely ignores the complexity of the drawVertices case where exp licit local coords
243 // are provided by the caller.
244 GrTextureParams::FilterMode textureFilterMode = GrTextureParams::kBilerp_Fil terMode;
245 switch (paint.getFilterQuality()) {
246 case kNone_SkFilterQuality:
247 textureFilterMode = GrTextureParams::kNone_FilterMode;
248 break;
249 case kLow_SkFilterQuality:
250 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
251 break;
252 case kMedium_SkFilterQuality:{
253 SkMatrix matrix;
254 matrix.setConcat(viewM, this->getLocalMatrix());
255 if (matrix.getMinScale() < SK_Scalar1) {
256 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
257 } else {
258 // Don't trigger MIP level generation unnecessarily.
259 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
260 }
261 break;
262 }
263 case kHigh_SkFilterQuality:
264 default:
265 SkErrorInternals::SetError(kInvalidPaint_SkError,
266 "Sorry, I don't understand the filtering "
267 "mode you asked for. Falling back to "
268 "MIPMaps.");
269 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
270 break;
271
272 }
273
274 // TODO: support other tile modes
275 GrTextureParams params(kClamp_TileMode, textureFilterMode);
276 SkAutoTUnref<GrTexture> diffuseTexture(GrRefCachedBitmapTexture(context, fDi ffuseMap, &params));
277 if (!diffuseTexture) {
278 SkErrorInternals::SetError(kInternalError_SkError,
279 "Couldn't convert bitmap to texture.");
280 return false;
281 }
282
283 SkAutoTUnref<GrTexture> normalTexture(GrRefCachedBitmapTexture(context, fNor malMap, &params));
284 if (!normalTexture) {
285 SkErrorInternals::SetError(kInternalError_SkError,
286 "Couldn't convert bitmap to texture.");
287 return false;
288 }
289
290 GrColor lightColor = GrColorPackRGBA(SkColorGetR(fLight.fColor), SkColorGetG (fLight.fColor),
291 SkColorGetB(fLight.fColor), SkColorGetA (fLight.fColor));
292 GrColor ambientColor = GrColorPackRGBA(SkColorGetR(fAmbientColor), SkColorGe tG(fAmbientColor),
293 SkColorGetB(fAmbientColor), SkColorGe tA(fAmbientColor));
294
295 *fp = SkNEW_ARGS(LightingFP, (diffuseTexture, normalTexture, matrix,
296 fLight.fDirection, lightColor, ambientColor));
297 *color = GrColorPackA4(paint.getAlpha());
298 return true;
299 }
300
301 ////////////////////////////////////////////////////////////////////////////
302
303 class LightingView : public SampleView {
304 public:
robertphillips 2015/07/08 16:15:14 Can this be an AutoTUnref ?
jvanverth1 2015/07/08 19:58:06 Done, I think.
305 SkShader* fShader;
306 SkBitmap fDiffuseBitmap;
307 SkBitmap fNormalBitmap;
308 SkScalar fLightAngle;
309 SkScalar fAngleDelta;
310
311 LightingView() {
312 SkString diffusePath = GetResourcePath("brickwork-texture.jpg");
313 SkImageDecoder::DecodeFile(diffusePath.c_str(), &fDiffuseBitmap);
314 SkString normalPath = GetResourcePath("brickwork_normal-map.jpg");
315 SkImageDecoder::DecodeFile(normalPath.c_str(), &fNormalBitmap);
316
317 fLightAngle = 0.785f;
318 fAngleDelta = -0.01f;
319
320 LightingShader::Light light;
321 light.fColor = SkColorSetRGB(0xff, 0xff, 0xff);
322 light.fDirection.x = 0;
323 light.fDirection.y = SkScalarSin(fLightAngle);
324 light.fDirection.z = SkScalarCos(fLightAngle);
325
326 SkColor ambient = SkColorSetRGB(0x1f, 0x1f, 0x1f);
327
328 fShader = new LightingShader(fDiffuseBitmap, fNormalBitmap, light, ambie nt);
329 }
330
331 virtual ~LightingView() {
332 SkSafeUnref(fShader);
333 }
334
335 protected:
336 // overrides from SkEventSink
337 bool onQuery(SkEvent* evt) override {
338 if (SampleCode::TitleQ(*evt)) {
339 SampleCode::TitleR(evt, "Lighting");
340 return true;
341 }
342 return this->INHERITED::onQuery(evt);
343 }
344
345 void onDrawContent(SkCanvas* canvas) override {
346 fLightAngle += fAngleDelta;
347 if (fLightAngle > 0.785f) {
348 fAngleDelta = -0.01f;
349 } else if (fLightAngle < -0.785f) {
350 fAngleDelta = 0.01f;
351 }
352
robertphillips 2015/07/08 16:15:14 Color animation ?
jvanverth1 2015/07/08 19:58:06 Done.
353 LightingShader::Light light;
354 light.fColor = SkColorSetRGB(0xff, 0xff, 0xff);
355 light.fDirection.x = 0;
356 light.fDirection.y = SkScalarSin(fLightAngle);
357 light.fDirection.z = SkScalarCos(fLightAngle);
358
robertphillips 2015/07/08 16:15:14 Can we just store it as a LightingShader ?
jvanverth1 2015/07/08 19:58:06 Done.
359 reinterpret_cast<LightingShader*>(fShader)->setLight(light);
360
361 SkPaint paint;
362 paint.setShader(fShader);
363
364 SkRect r;
365 int w = fDiffuseBitmap.width();
366 int h = fDiffuseBitmap.height();
367 r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
368
369 canvas->drawRect(r, paint);
370
371 // so we're constantly updating
372 this->inval(NULL);
373 }
374
375 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) ove rride {
376 this->inval(NULL);
377 return this->INHERITED::onFindClickHandler(x, y, modi);
378 }
379
robertphillips 2015/07/08 16:15:14 rm this ?
jvanverth1 2015/07/08 19:58:06 Done.
380 bool onClick(Click* click) override {
381 return this->INHERITED::onClick(click);
382 }
383
384 private:
385 typedef SampleView INHERITED;
386 };
387
388 //////////////////////////////////////////////////////////////////////////////
389
390 static SkView* MyFactory() { return new LightingView; }
391 static SkViewRegister reg(MyFactory);
OLDNEW
« no previous file with comments | « resources/brickwork_normal-map.jpg ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698