blob: 868ce35244288fa99b9c76c4ff0c75705650c173 [file] [log] [blame]
dvonbeck6d391b62016-08-18 08:55:48 -07001/*
2 * Copyright 2016 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
8#include "SampleCode.h"
9#include "SkCanvas.h"
10#include "SkLightingShader.h"
11#include "SkNormalSource.h"
12#include "sk_tool_utils.h"
13
14
15class BevelView : public SampleView {
16public:
17 BevelView()
18 : fShapeBounds(SkRect::MakeWH(kShapeBoundsSize, kShapeBoundsSize))
19 , fRedLight(SkLights::Light::MakeDirectional(SkColor3f::Make(0.6f, 0.45f, 0.3f),
20 SkVector3::Make(0.0f, -5.0f, 1.0f)))
21 , fBlueLight(SkLights::Light::MakeDirectional(SkColor3f::Make(0.3f, 0.45f, 0.6f),
22 SkVector3::Make(0.0f, 5.0f, 1.0f))) {
23 this->setBGColor(0xFF666868); // Slightly colorized gray for contrast
24
25 // Lights
26 SkLights::Builder builder;
27 builder.add(fRedLight);
28 builder.add(fBlueLight);
29 builder.add(SkLights::Light::MakeAmbient(SkColor3f::Make(0.4f, 0.4f, 0.4f)));
30 fLights = builder.finish();
31
32 // Controls
33
34 SkScalar currY = kSliderHeight;
35
36 const SkScalar kWidthCtrlInitialPos = 0.2f;
37 fCtrlRangeRects[0] = SkRect::MakeXYWH(0.0f, currY,
38 kCtrlRange + kSliderWidth,
39 kSliderHeight);
40 fWidthCtrlRect = SkRect::MakeXYWH(kWidthCtrlInitialPos * kCtrlRange, currY,
41 kSliderWidth, kSliderHeight);
42 fBevelWidth = kBevelWidthMax * kWidthCtrlInitialPos;
43 currY += 2 * kSliderHeight;
44
45 const SkScalar kHeightCtrlInitialPos = 0.75f;
46 fCtrlRangeRects[1] = SkRect::MakeXYWH(0.0f, currY,
47 kCtrlRange + kSliderWidth,
48 kSliderHeight);
49 fHeightCtrlRect = SkRect::MakeXYWH(kHeightCtrlInitialPos * kCtrlRange, currY,
50 kSliderWidth, kSliderHeight);
51 // Mapping from (0, 1) to (-1, 1)
52 fBevelHeight = kBevelHeightMax * (kHeightCtrlInitialPos * 2.0f - 1.0f);
53 currY += 2 * kSliderHeight;
54
55 const SkScalar kTypeCtrlInitialPos = 1.0f / (2.0f * kBevelTypeCount);
56 fCtrlRangeRects[2] = SkRect::MakeXYWH(0.0f, currY,
57 kCtrlRange + kSliderWidth,
58 kSliderHeight);
59 fTypeCtrlRect = SkRect::MakeXYWH(kTypeCtrlInitialPos * kCtrlRange, currY,
60 kSliderWidth, kSliderHeight);
61 fBevelType = (SkNormalSource::BevelType) SkScalarFloorToInt(kTypeCtrlInitialPos);
62 currY += 2 * kSliderHeight;
63
64 fSelectedCtrlRect = nullptr;
65 fDirtyNormalSource = true;
66
67 fLabelTypeface = sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle());
68 }
69
70protected:
71 bool onQuery(SkEvent *evt) override {
72 if (SampleCode::TitleQ(*evt)) {
73 SampleCode::TitleR(evt, "Bevel");
74 return true;
75 }
76
77 return this->INHERITED::onQuery(evt);
78 }
79
80 enum Shape {
81 kCircle_Shape,
82 kRect_Shape,
83 };
84 void drawShape(enum Shape shape, SkCanvas* canvas) {
85 canvas->save();
86
87 SkPaint paint;
88
89 if (fDirtyNormalSource) {
90 fNormalSource = SkNormalSource::MakeBevel(fBevelType, fBevelWidth, fBevelHeight);
91 fDirtyNormalSource = false;
92 }
93
94 paint.setShader(SkLightingShader::Make(nullptr, fNormalSource, fLights));
95 paint.setAntiAlias(true);
96 paint.setColor(0xFFDDDDDD);
97 switch (shape) {
98 case kCircle_Shape:
99 canvas->drawCircle(fShapeBounds.centerX(), fShapeBounds.centerY(),
100 fShapeBounds.width()/2.0f, paint);
101 break;
102 case kRect_Shape:
103 canvas->drawRect(fShapeBounds, paint);
104 break;
105 default:
106 SkDEBUGFAIL("Invalid shape enum for drawShape");
107 }
108
109 canvas->restore();
110 }
111
112 void onDrawContent(SkCanvas *canvas) override {
113
114 canvas->save();
115 canvas->resetMatrix(); // Force static controls and labels
116
117 // Draw controls
118
119 SkPaint ctrlRectPaint;
120 ctrlRectPaint.setColor(0xFFF3F3F3);
121 canvas->drawRect(fWidthCtrlRect, ctrlRectPaint);
122 canvas->drawRect(fHeightCtrlRect, ctrlRectPaint);
123 canvas->drawRect(fTypeCtrlRect, ctrlRectPaint);
124
125 SkPaint ctrlRectRangePaint;
126 ctrlRectRangePaint.setColor(0xFFFFFFFF);
127 ctrlRectRangePaint.setStyle(SkPaint::kStroke_Style);
128 ctrlRectRangePaint.setStrokeWidth(2.0f);
129
130 for (size_t i = 0; i < kNumControls; i++) {
131 canvas->drawRect(fCtrlRangeRects[i], ctrlRectRangePaint);
132 }
133
134 // Draw labels
135 constexpr SkScalar kTextSize = 12.0f;
136 SkString widthLabel, heightLabel, typeLabel;
137 SkPaint labelPaint;
138 labelPaint.setTypeface(fLabelTypeface);
139 labelPaint.setAntiAlias(true);
140 labelPaint.setColor(0xFFFFFFFF);
141 labelPaint.setTextSize(kTextSize);
142
143 widthLabel.appendf("BevelWidth: %f", fBevelWidth);
144 heightLabel.appendf("BevelHeight: %f", fBevelHeight);
145 typeLabel.append("BevelType: ");
146
147 switch (fBevelType) {
148 case SkNormalSource::BevelType::kLinear:
149 typeLabel.append("Linear");
150 break;
151 case SkNormalSource::BevelType::kRoundedIn:
152 typeLabel.append("RoundedIn");
153 break;
154 case SkNormalSource::BevelType::kRoundedOut:
155 typeLabel.append("RoundedOut");
156 break;
157 }
158
159 canvas->drawText(widthLabel.c_str(), widthLabel.size(), 0,
160 fWidthCtrlRect.fTop - kTextSize/2.0f, labelPaint);
161 canvas->drawText(heightLabel.c_str(), heightLabel.size(), 0,
162 fHeightCtrlRect.fTop - kTextSize/2.0f, labelPaint);
163 canvas->drawText(typeLabel.c_str(), typeLabel.size(), 0,
164 fTypeCtrlRect.fTop - kTextSize/2.0f, labelPaint);
165
166 canvas->restore(); // Return to modified matrix when drawing shapes
167
168 // Draw shapes
169 SkScalar xPos = kCtrlRange + 25.0f;
170 SkScalar yPos = fShapeBounds.height();
171 for (Shape shape : { kCircle_Shape, kRect_Shape }) {
172 canvas->save();
173 canvas->translate(xPos, yPos);
174 this->drawShape(shape, canvas);
175 canvas->restore();
176
177 xPos += 1.2f * fShapeBounds.width();
178 }
179 }
180
181 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
182 return new SkView::Click(this);
183 }
184
185 bool onClick(Click *click) override {
186 SkScalar x = click->fCurr.fX;
187 SkScalar y = click->fCurr.fY;
188
189 SkScalar dx = x - click->fPrev.fX;
190 SkScalar dy = y - click->fPrev.fY;
191
192 // Control deselection
193 if (Click::State::kUp_State == click->fState) {
194 fSelectedCtrlRect = nullptr;
195 return true;
196 }
197
198 // Control selection
199 if (nullptr == fSelectedCtrlRect && Click::State::kDown_State == click->fState) {
200 if (fWidthCtrlRect.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
201 fSelectedCtrlRect = &fWidthCtrlRect;
202 } else if (fHeightCtrlRect.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
203 fSelectedCtrlRect = &fHeightCtrlRect;
204 } else if (fTypeCtrlRect.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
205 fSelectedCtrlRect = &fTypeCtrlRect;
206 }
207 }
208
209 if (nullptr != fSelectedCtrlRect) { // Control modification
210 fSelectedCtrlRect->offsetTo(SkScalarPin(x, 0.0f, kCtrlRange), fSelectedCtrlRect->fTop);
211
212 fBevelHeight = (fHeightCtrlRect.fLeft / kCtrlRange) * kBevelHeightMax * 2.0f
213 - kBevelHeightMax;
214 fBevelWidth = (fWidthCtrlRect.fLeft / kCtrlRange) * kBevelWidthMax;
215 fBevelType = (SkNormalSource::BevelType)SkTMin(
216 SkScalarFloorToInt(kBevelTypeCount * fTypeCtrlRect.fLeft / kCtrlRange),
217 kBevelTypeCount - 1);
218
219 // Snap type controls to 3 positions
220 fTypeCtrlRect.offsetTo(kCtrlRange * ( ((int)fBevelType)/SkIntToScalar(kBevelTypeCount)
221 + 1.0f/(2.0f * kBevelTypeCount) ),
222 fTypeCtrlRect.fTop);
223
224 // Ensuring width is non-zero
225 fBevelWidth = SkMaxScalar(1.0f, fBevelWidth);
226
227 fDirtyNormalSource = true;
228
229 this->inval(nullptr);
230 return true;
231 } else { // Moving light
232 if (dx != 0 || dy != 0) {
233 float recipX = 1.0f / kAppWidth;
234 float recipY = 1.0f / kAppHeight;
235
236 if (0 == click->fModifierKeys) { // No modifier
237 fBlueLight = SkLights::Light::MakeDirectional(fBlueLight.color(),
238 SkVector3::Make((kAppWidth/2.0f - x) * recipX * -3.0f,
239 (kAppHeight/2.0f - y) * recipY * -3.0f,
240 1.0f));
241 } else if (1 == click->fModifierKeys) { // Shift key
242 fRedLight = SkLights::Light::MakeDirectional(fRedLight.color(),
243 SkVector3::Make((kAppWidth/2.0f - x) * recipX * -3.0f,
244 (kAppHeight/2.0f - y) * recipY * -3.0f,
245 1.0f));
246 }
247
248 SkLights::Builder builder;
249 builder.add(fRedLight);
250 builder.add(fBlueLight);
251 builder.add(SkLights::Light::MakeAmbient(
252 SkColor3f::Make(0.4f, 0.4f, 0.4f)));
253 fLights = builder.finish();
254
255 this->inval(nullptr);
256 }
257 return true;
258 }
259
260 return true;
261 }
262
263private:
264 static constexpr int kNumTestRects = 3;
265
266 static constexpr SkScalar kAppWidth = 400.0f;
267 static constexpr SkScalar kAppHeight = 400.0f;
268 static constexpr SkScalar kShapeBoundsSize = 120.0f;
269
270 static constexpr SkScalar kCtrlRange = 150.0f;
271 static constexpr SkScalar kBevelWidthMax = kShapeBoundsSize;
272 static constexpr SkScalar kBevelHeightMax = 50.0f;
273 static constexpr int kBevelTypeCount = 3;
274
275 static constexpr SkScalar kSliderHeight = 20.0f;
276 static constexpr SkScalar kSliderWidth = 10.0f;
277
278 const SkRect fShapeBounds;
279
280 static constexpr int kNumControls = 3;
281 SkRect fCtrlRangeRects[kNumControls];
282 SkRect* fSelectedCtrlRect;
283 SkRect fWidthCtrlRect;
284 SkRect fHeightCtrlRect;
285 SkRect fTypeCtrlRect;
286
287 SkScalar fBevelWidth;
288 SkScalar fBevelHeight;
289 SkNormalSource::BevelType fBevelType;
290 sk_sp<SkNormalSource> fNormalSource;
291 bool fDirtyNormalSource;
292
293 sk_sp<SkLights> fLights;
294 SkLights::Light fRedLight;
295 SkLights::Light fBlueLight;
296
297 sk_sp<SkTypeface> fLabelTypeface;
298
299 typedef SampleView INHERITED;
300};
301
302//////////////////////////////////////////////////////////////////////////////
303
304static SkView* MyFactory() { return new BevelView; }
305static SkViewRegister reg(MyFactory);
306