Chromium Code Reviews| Index: samplecode/SampleShadowing.cpp |
| diff --git a/samplecode/SampleShadowing.cpp b/samplecode/SampleShadowing.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..763a1ef3bd7ba0bdb0c1cd23e8aa97f3e14899db |
| --- /dev/null |
| +++ b/samplecode/SampleShadowing.cpp |
| @@ -0,0 +1,356 @@ |
| +/* |
| + * Copyright 2016 Google Inc. |
| + * |
| + * Use of this source code is governed by a BSD-style license that can be |
| + * found in the LICENSE file. |
| + */ |
| + |
|
robertphillips
2016/08/03 18:47:48
Why gm.h?
vjiaoblack
2016/08/04 13:36:22
Done.
|
| +#include "gm.h" |
| +#include "SampleCode.h" |
| +#include "SkPictureRecorder.h" |
| +#include "SkSurface.h" |
| +#include "SkShadowPaintFilterCanvas.h" |
| +#include "SkShadowShader.h" |
| + |
| +#ifdef SK_EXPERIMENTAL_SHADOWING |
| + |
|
robertphillips
2016/08/03 18:47:47
Can this be a class scope constant?
vjiaoblack
2016/08/04 13:36:22
Done.
|
| +constexpr int NUM_TEST_RECTS = 3; |
| + |
| +static sk_sp<SkShader> make_shadow_shader(sk_sp<SkImage> povDepth, |
| + sk_sp<SkImage> diffuse, |
| + sk_sp<SkLights> lights) { |
| + |
| + sk_sp<SkShader> povDepthShader = povDepth->makeShader(SkShader::kClamp_TileMode, |
| + SkShader::kClamp_TileMode); |
| + |
| + sk_sp<SkShader> diffuseShader = diffuse->makeShader(SkShader::kClamp_TileMode, |
| + SkShader::kClamp_TileMode); |
| + |
| + return SkShadowShader::Make(std::move(povDepthShader), |
| + std::move(diffuseShader), |
| + std::move(lights), |
| + diffuse->width(), diffuse->height()); |
| +} |
| + |
| + |
| +class IndexClick : public SkView::Click { |
|
robertphillips
2016/08/03 18:47:47
move this to the private block ?
vjiaoblack
2016/08/04 13:36:22
Done.
|
| + int fIndex; |
| +public: |
| + IndexClick(SkView* v, int index) : INHERITED(v), fIndex(index) {} |
| + |
| + static int GetIndex(SkView::Click* click) { |
| + return ((IndexClick*)click)->fIndex; |
| + } |
| + |
| +private: |
| + typedef SkView::Click INHERITED; |
| +}; |
| + |
| +class ShadowingView : public SampleView { |
|
robertphillips
2016/08/03 18:47:48
Make this "static const int kZoom = 96;" down in t
vjiaoblack
2016/08/04 13:36:22
Done.
|
| + enum { |
| + kZoom = 96 |
| + }; |
| + |
| +public: |
| + ShadowingView() { |
| + |
| + this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC)); |
| + SkLights::Builder builder; |
| + builder.add(SkLights::Light(SkColor3f::Make(0.2f, 0.3f, 0.4f), |
| + SkVector3::Make(0.27f, 0.07f, 1.0f))); |
| + builder.add(SkLights::Light(SkColor3f::Make(0.4f, 0.3f, 0.2f), |
| + SkVector3::Make(0.03f, 0.27f, 1.0f))); |
| + builder.add(SkLights::Light(SkColor3f::Make(0.4f, 0.4f, 0.4f))); |
| + fLights = builder.finish(); |
| + |
| + fColors[0] = 0xFFEE8888; |
| + fDepths[0] = 80; |
| + fRects[0] = SkRect::MakeLTRB(200,150,350,300); |
| + |
| + fColors[1] = 0xFF88EE88; |
| + fDepths[1] = 160; |
| + fRects[1] = SkRect::MakeLTRB(150,200,300,350); |
| + |
| + fColors[2] = 0xFF8888EE; |
| + fDepths[2] = 240; |
| + fRects[2] = SkRect::MakeLTRB(100,100,250,250); |
| + |
| + fUpdateDiffuseMap = true; |
| + fUpdatePovDepthMap = true; |
| + fUpdatePicture = true; |
| + fUpdateDepthMaps = true; |
| + |
| + } |
| + |
| +protected: |
|
robertphillips
2016/08/03 18:47:48
Can all these member variables be private ?
vjiaoblack
2016/08/04 13:36:22
Done.
|
| + static const int kWidth = 400; |
| + static const int kHeight = 400; |
|
robertphillips
2016/08/03 18:47:48
Maybe have:
struct {
SkRect fGeometry;
int
vjiaoblack
2016/08/04 13:36:22
Done.
|
| + SkRect fRects[NUM_TEST_RECTS]; |
| + int fDepths[NUM_TEST_RECTS]; |
| + SkColor fColors[NUM_TEST_RECTS]; |
|
robertphillips
2016/08/03 18:47:48
You initialize all the other guys in the ctor.
vjiaoblack
2016/08/04 13:36:22
Done.
|
| + int fSelectedRect = -1; |
| + bool fMoveLight = false; |
| + |
| + sk_sp<SkImage> fPovDepthMap; |
| + sk_sp<SkImage> fDiffuseMap; |
| + sk_sp<SkPicture> fPicture; |
| + |
| + bool fUpdateDiffuseMap; |
| + bool fUpdatePovDepthMap; |
| + bool fUpdatePicture; |
| + bool fUpdateDepthMaps; |
| + |
| + bool onQuery(SkEvent *evt) override { |
| + if (SampleCode::TitleQ(*evt)) { |
| + SampleCode::TitleR(evt, "shadowing"); |
| + return true; |
| + } |
| + |
| + SkUnichar uni; |
| + if (SampleCode::CharQ(*evt, &uni)) { |
| + switch (uni) { |
| + case 'L': |
| + fMoveLight = !fMoveLight; |
| + break; |
| + default: |
| + break; |
| + } |
| + } |
| + return this->INHERITED::onQuery(evt); |
| + } |
| + |
| + sk_sp<SkPicture> makeTestPicture(int width, int height) { |
| + SkPictureRecorder recorder; |
| + |
| + // LONG RANGE TODO: eventually add SkBBHFactory (bounding box factory) |
| + SkCanvas* canvas = recorder.beginRecording(SkRect::MakeIWH(width, height)); |
| + |
| + SkASSERT(canvas->getTotalMatrix().isIdentity()); |
| + SkPaint paint; |
| + paint.setColor(SK_ColorGRAY); |
| + |
| + // LONG RANGE TODO: tag occluders |
| + // LONG RANGE TODO: track number of IDs we need (hopefully less than 256) |
| + // and determinate the mapping from z to id |
| + |
| + // universal receiver, "ground" |
| + canvas->drawRect(SkRect::MakeIWH(width, height), paint); |
| + |
| + for (int i = 0; i < NUM_TEST_RECTS; i++) { |
| + paint.setColor(fColors[i]); |
| + if (i == 0) { |
| + canvas->translateZ(fDepths[0]); |
| + } else { |
| + canvas->translateZ(fDepths[i] - fDepths[i-1]); |
| + } |
| + canvas->drawRect(fRects[i], paint); |
| + } |
| + |
| + return recorder.finishRecordingAsPicture(); |
| + } |
| + |
| + void updateDepthMaps(SkCanvas *canvas) { |
| + for (int i = 0; i < fLights->numLights(); ++i) { |
| + // skip over ambient lights; they don't cast shadows |
| + if (SkLights::Light::kAmbient_LightType == fLights->light(i).type()) { |
| + continue; |
| + } |
| + |
| + // TODO: maybe add a kDepth_8_SkColorType when vertices have depth |
| + |
| + // assume max depth is 255. |
| + // TODO: find actual max depth of picture |
|
robertphillips
2016/08/03 18:47:48
Can this computation be a sub routine:
static SkI
vjiaoblack
2016/08/04 13:36:22
Done.
|
| + int maxDepth = 255; |
| + int dMapWidth = SkMin32(maxDepth * fabs(fLights->light(i).dir().fX) + kWidth, |
|
robertphillips
2016/08/03 18:47:47
line up ?
vjiaoblack
2016/08/04 13:36:22
Done.
|
| + kWidth * 2); |
| + int dMapHeight = SkMin32(maxDepth * fabs(fLights->light(i).dir().fY) + kHeight, |
|
robertphillips
2016/08/03 18:47:48
line up ?
vjiaoblack
2016/08/04 13:36:22
Done.
|
| + kHeight * 2); |
| + |
| + SkImageInfo info = SkImageInfo::Make(dMapWidth, dMapHeight, |
| + kBGRA_8888_SkColorType, |
| + kOpaque_SkAlphaType); |
| + |
| + // Create a new surface (that matches the backend of canvas) |
| + // for each shadow map |
| + sk_sp<SkSurface> surf(canvas->makeSurface(info)); |
| + |
| + // Wrap another SPFCanvas around the surface |
| + sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas = |
| + sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas()); |
| + |
| + // set the depth map canvas to have the light we're drawing. |
| + SkLights::Builder builder; |
| + builder.add(fLights->light(i)); |
| + sk_sp<SkLights> curLight = builder.finish(); |
| + |
| + depthMapCanvas->setLights(std::move(curLight)); |
| + depthMapCanvas->drawPicture(fPicture); |
| + |
| + fLights->light(i).setShadowMap(surf->makeImageSnapshot()); |
| + } |
| + } |
| + |
| + void updatePovDepthMap(SkCanvas* canvas) { |
| + // TODO: pass the depth to the shader in vertices, or uniforms |
| + // so we don't have to render depth and color separately |
| + |
| + SkLights::Builder builder; |
| + builder.add(SkLights::Light(SkColor3f::Make(1.0f, 1.0f, 1.0f), |
| + SkVector3::Make(0.0f, 0.0f, 1.0f))); |
| + sk_sp<SkLights> povLight = builder.finish(); |
| + |
| + SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, |
| + kBGRA_8888_SkColorType, |
| + kOpaque_SkAlphaType); |
| + |
| + // Create a new surface (that matches the backend of canvas) |
| + // to create the povDepthMap |
| + sk_sp<SkSurface> surf(canvas->makeSurface(info)); |
| + |
| + // Wrap another SPFCanvas around the surface |
| + sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas = |
| + sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas()); |
| + |
| + // set the depth map canvas to have the light as the user's POV |
| + depthMapCanvas->setLights(std::move(povLight)); |
| + |
| + depthMapCanvas->drawPicture(fPicture); |
| + |
| + fPovDepthMap = surf->makeImageSnapshot(); |
| + } |
| + |
| + void updateDiffuseMap(SkCanvas* canvas) { |
| + SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, |
| + kBGRA_8888_SkColorType, |
| + kOpaque_SkAlphaType); |
| + |
| + sk_sp<SkSurface> surf(canvas->makeSurface(info)); |
| + surf->getCanvas()->drawPicture(fPicture); |
| + |
| + fDiffuseMap = surf->makeImageSnapshot(); |
| + } |
| + |
|
robertphillips
2016/08/03 18:47:48
rm this TODO ?
vjiaoblack
2016/08/04 13:36:22
Done.
|
| + // TODO why does this get slower after time approaches |
| + void onDrawContent(SkCanvas *canvas) override { |
| + if (fUpdatePicture || !fPicture) { |
|
robertphillips
2016/08/03 18:47:48
add this-> for member function calls here & below
vjiaoblack
2016/08/04 13:36:22
Done.
|
| + fPicture = makeTestPicture(kWidth, kHeight); |
| + fUpdatePicture = false; |
| + } |
| + |
| + if (fUpdateDepthMaps || !fPovDepthMap) { |
| + updateDepthMaps(canvas); |
| + fUpdateDepthMaps = false; |
| + } |
| + |
| + if (fUpdatePovDepthMap || !fPovDepthMap) { |
| + updatePovDepthMap(canvas); |
| + fUpdatePovDepthMap = false; |
| + } |
| + |
| + if (fUpdateDiffuseMap || !fDiffuseMap) { |
| + updateDiffuseMap(canvas); |
| + fUpdateDiffuseMap = false; |
| + } |
| + |
| + SkPaint paint; |
|
robertphillips
2016/08/03 18:47:48
I don't think you want to std::move here
vjiaoblack
2016/08/04 13:36:22
I see. Since we need it next frame as well (perhap
|
| + paint.setShader(make_shadow_shader(std::move(fPovDepthMap), |
| + std::move(fDiffuseMap), |
| + fLights)); |
| + |
| + canvas->drawRect(SkRect::MakeIWH(kWidth, kHeight), paint); |
| + } |
| + |
| + SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override { |
| + int index = 0; |
| + |
| + return new IndexClick(this, index); |
| + } |
| + |
| + bool onClick(Click *click) override { |
| + SkScalar x = click->fCurr.fX; |
| + SkScalar y = click->fCurr.fY; |
| + |
| + SkScalar dx = x - click->fPrev.fX; |
| + SkScalar dy = y - click->fPrev.fY; |
| + |
| + if (fMoveLight) { |
| + if (dx != 0 && dy != 0) { |
| + float recipX = 1.0f / kWidth; |
| + float recipY = 1.0f / kHeight; |
| + |
| + SkLights::Builder builder; |
| + builder.add(SkLights::Light(SkColor3f::Make(0.2f, 0.3f, 0.4f), |
| + SkVector3::Make(0.12f + (200.0f - x) * recipX, |
| + -0.08f + (200.0f - y) * recipY, |
| + 1.0f))); |
| + builder.add(SkLights::Light(SkColor3f::Make(0.4f, 0.3f, 0.2f), |
| + SkVector3::Make(-0.12f + (200.0f - x) * recipX, |
| + 0.12f + (200.0f - y) * recipY, |
| + 1.0f))); |
| + builder.add(SkLights::Light(SkColor3f::Make(0.4f, 0.4f, 0.4f))); |
| + fLights = builder.finish(); |
| + |
| + fUpdateDepthMaps = true; |
| + } |
| + |
| + return true; |
|
robertphillips
2016/08/03 18:47:48
extra '\n'
vjiaoblack
2016/08/04 13:36:22
Done.
|
| + |
| + } |
| + |
| + if (click->fState == Click::State::kUp_State) { |
| + fSelectedRect = -1; |
| + return true; |
| + } |
| + |
| + if (fSelectedRect > -1) { |
| + SkScalar x = click->fCurr.fX; |
| + SkScalar y = click->fCurr.fY; |
| + |
| + SkScalar dx = x - click->fPrev.fX; |
| + SkScalar dy = y - click->fPrev.fY; |
| + |
| + fRects[fSelectedRect].fLeft += dx; |
| + fRects[fSelectedRect].fRight += dx; |
| + fRects[fSelectedRect].fTop += dy; |
| + fRects[fSelectedRect].fBottom += dy; |
| + |
|
robertphillips
2016/08/03 18:47:48
It seems like you actually have two states:
fScen
vjiaoblack
2016/08/04 13:36:22
Done.
Seems like the slowest part of the loop is
|
| + fUpdateDepthMaps = true; |
| + fUpdatePovDepthMap = true; |
| + fUpdatePicture = true; |
| + fUpdateDiffuseMap = true; |
| + |
| + return true; |
| + } |
| + |
| + // assume last elements are highest |
| + for (int i = NUM_TEST_RECTS - 1; i >= 0; i--) { |
| + if (fRects[i].contains(SkRect::MakeXYWH(x, y, 1, 1))) { |
| + fSelectedRect = i; |
| + fRects[i].fLeft += dx; |
| + fRects[i].fRight += dx; |
| + fRects[i].fTop += dy; |
| + fRects[i].fBottom += dy; |
| + |
| + fUpdateDepthMaps = true; |
| + fUpdatePovDepthMap = true; |
| + fUpdatePicture = true; |
| + fUpdateDiffuseMap = true; |
| + |
| + break; |
| + } |
| + } |
| + |
| + return true; |
| + } |
| + |
| +private: |
| + sk_sp<SkLights> fLights; |
| + |
| + typedef SampleView INHERITED; |
| +}; |
| + |
| +////////////////////////////////////////////////////////////////////////////// |
| +static SkView* MyFactory() { return new ShadowingView; } |
| +static SkViewRegister reg(MyFactory); |
| + |
| +#endif |