OLD | NEW |
---|---|
(Empty) | |
1 /* | |
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 | |
15 class BevelView : public SampleView { | |
16 public: | |
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.45 f, 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.4 f))); | |
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); | |
robertphillips
2016/08/17 21:52:13
Well, since Greg sort of brought it up, would it m
dvonbeck
2016/08/17 22:10:22
I am actually working on this for my next CL. I am
robertphillips
2016/08/18 14:40:41
Okay - let's leave it for the follow on.
dvonbeck
2016/08/18 15:12:14
Acknowledged.
| |
40 fWidthCtrlRect = SkRect::MakeXYWH(kWidthCtrlInitialPos * kCtrlRange, cur rY, | |
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, c urrY, | |
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(kTypeCtrlIni tialPos); | |
62 currY += 2 * kSliderHeight; | |
63 | |
64 fSelectedCtrlRect = nullptr; | |
65 } | |
66 | |
67 protected: | |
68 bool onQuery(SkEvent *evt) override { | |
69 if (SampleCode::TitleQ(*evt)) { | |
70 SampleCode::TitleR(evt, "bevel"); | |
egdaniel
2016/08/18 14:33:28
We genearaly name samples with a capital letter an
dvonbeck
2016/08/18 15:12:14
Done.
| |
71 return true; | |
72 } | |
73 | |
74 return this->INHERITED::onQuery(evt); | |
75 } | |
76 | |
77 enum Shape { | |
78 kCircle_Shape, | |
79 kRect_Shape, | |
80 }; | |
81 void drawShape(enum Shape shape, SkCanvas* canvas) { | |
82 canvas->save(); | |
83 | |
84 SkPaint paint; | |
85 | |
robertphillips
2016/08/18 14:40:41
We should probably be caching this and only recrea
dvonbeck
2016/08/18 15:12:13
Done.
| |
86 sk_sp<SkNormalSource> normalSource = SkNormalSource::MakeBevel(fBevelTyp e, fBevelWidth, | |
87 fBevelHei ght); | |
88 | |
89 paint.setShader(SkLightingShader::Make(nullptr, std::move(normalSource), fLights)); | |
90 paint.setAntiAlias(true); | |
91 paint.setColor(0xFFDDDDDD); | |
92 switch (shape) { | |
93 case kCircle_Shape: | |
94 canvas->drawCircle(fShapeBounds.centerX(), fShapeBounds.centerY( ), | |
95 fShapeBounds.width()/2.0f, paint); | |
96 break; | |
97 case kRect_Shape: | |
98 canvas->drawRect(fShapeBounds, paint); | |
99 break; | |
100 default: | |
101 SkDEBUGFAIL("Invalid shape enum for drawShape"); | |
102 } | |
103 | |
104 canvas->restore(); | |
105 } | |
106 | |
107 void onDrawContent(SkCanvas *canvas) override { | |
108 | |
109 canvas->save(); | |
110 canvas->resetMatrix(); // Force static controls and labels | |
111 | |
112 // Draw controls | |
113 | |
114 SkPaint ctrlRectPaint; | |
115 ctrlRectPaint.setColor(0xFFF3F3F3); | |
116 canvas->drawRect(fWidthCtrlRect, ctrlRectPaint); | |
117 canvas->drawRect(fHeightCtrlRect, ctrlRectPaint); | |
118 canvas->drawRect(fTypeCtrlRect, ctrlRectPaint); | |
119 | |
120 SkPaint ctrlRectRangePaint; | |
121 ctrlRectRangePaint.setColor(0xFFFFFFFF); | |
122 ctrlRectRangePaint.setStyle(SkPaint::kStroke_Style); | |
123 ctrlRectRangePaint.setStrokeWidth(2.0f); | |
124 | |
125 for (size_t i = 0; i < kNumControls; i++) { | |
126 canvas->drawRect(fCtrlRangeRects[i], ctrlRectRangePaint); | |
127 } | |
128 | |
129 // Draw labels | |
130 constexpr SkScalar kTextSize = 12.0f; | |
131 SkString widthLabel, heightLabel, typeLabel; | |
132 SkPaint labelPaint; | |
robertphillips
2016/08/18 14:40:41
Can we cache off the typeface and reuse it ?
dvonbeck
2016/08/18 15:12:14
Done.
| |
133 labelPaint.setTypeface(sk_tool_utils::create_portable_typeface("sans-ser if", | |
134 SkFontSty le())); | |
135 labelPaint.setAntiAlias(true); | |
136 labelPaint.setColor(0xFFFFFFFF); | |
137 labelPaint.setTextSize(kTextSize); | |
138 | |
139 widthLabel.appendf("BevelWidth: %f", fBevelWidth); | |
140 heightLabel.appendf("BevelHeight: %f", fBevelHeight); | |
141 typeLabel.append("BevelType: "); | |
142 | |
143 switch (fBevelType) { | |
144 case SkNormalSource::BevelType::kLinear: | |
145 typeLabel.append("Linear"); | |
146 break; | |
147 case SkNormalSource::BevelType::kRoundedIn: | |
148 typeLabel.append("RoundedIn"); | |
149 break; | |
150 case SkNormalSource::BevelType::kRoundedOut: | |
151 typeLabel.append("RoundedOut"); | |
152 break; | |
153 } | |
154 | |
155 canvas->drawText(widthLabel.c_str(), widthLabel.size(), 0, | |
156 fWidthCtrlRect.fTop - kTextSize/2.0f, labelPaint); | |
157 canvas->drawText(heightLabel.c_str(), heightLabel.size(), 0, | |
158 fHeightCtrlRect.fTop - kTextSize/2.0f, labelPaint); | |
159 canvas->drawText(typeLabel.c_str(), typeLabel.size(), 0, | |
160 fTypeCtrlRect.fTop - kTextSize/2.0f, labelPaint); | |
161 | |
162 canvas->restore(); // Return to modified matrix when drawing shapes | |
163 | |
164 // Draw shapes | |
165 SkScalar xPos = kCtrlRange + 25.0f; | |
166 SkScalar yPos = fShapeBounds.height(); | |
167 for (Shape shape : { kCircle_Shape, kRect_Shape }) { | |
168 canvas->save(); | |
169 canvas->translate(xPos, yPos); | |
170 this->drawShape(shape, canvas); | |
171 canvas->restore(); | |
172 | |
173 xPos += 1.2f * fShapeBounds.width(); | |
174 } | |
175 } | |
176 | |
177 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) ove rride { | |
178 return new SkView::Click(this); | |
179 } | |
180 | |
181 bool onClick(Click *click) override { | |
182 SkScalar x = click->fCurr.fX; | |
183 SkScalar y = click->fCurr.fY; | |
184 | |
185 SkScalar dx = x - click->fPrev.fX; | |
186 SkScalar dy = y - click->fPrev.fY; | |
187 | |
188 // Control deselection | |
189 if (Click::State::kUp_State == click->fState) { | |
190 fSelectedCtrlRect = nullptr; | |
191 return true; | |
192 } | |
193 | |
194 // Control selection | |
195 if (nullptr == fSelectedCtrlRect && Click::State::kDown_State == click-> fState) { | |
196 if (fWidthCtrlRect.contains(SkRect::MakeXYWH(x, y, 1, 1))) { | |
197 fSelectedCtrlRect = &fWidthCtrlRect; | |
198 } else if (fHeightCtrlRect.contains(SkRect::MakeXYWH(x, y, 1, 1))) { | |
199 fSelectedCtrlRect = &fHeightCtrlRect; | |
200 } else if (fTypeCtrlRect.contains(SkRect::MakeXYWH(x, y, 1, 1))) { | |
201 fSelectedCtrlRect = &fTypeCtrlRect; | |
202 } | |
203 } | |
204 | |
205 // Control modification | |
206 if (nullptr != fSelectedCtrlRect) { | |
207 fSelectedCtrlRect->offsetTo(SkScalarPin(x, 0.0f, kCtrlRange), fSelec tedCtrlRect->fTop); | |
208 | |
209 fBevelHeight = (fHeightCtrlRect.fLeft / kCtrlRange) * kBevelHeightMa x * 2.0f | |
210 - kBevelHeightMax; | |
211 fBevelWidth = (fWidthCtrlRect.fLeft / kCtrlRange) * kBevelWidthMax; | |
212 fBevelType = (SkNormalSource::BevelType)SkTMin( | |
213 SkScalarFloorToInt(kBevelTypeCount * fTypeCtrlRect.fLeft / k CtrlRange), | |
214 kBevelTypeCount - 1); | |
215 | |
216 // Snap type controls to 3 positions | |
217 fTypeCtrlRect.offsetTo(kCtrlRange * ( ((int)fBevelType)/SkIntToScala r(kBevelTypeCount) | |
218 + 1.0f/(2.0f * kBevelTypeCount ) ), | |
219 fTypeCtrlRect.fTop); | |
220 | |
221 // Ensuring width is non-zero | |
222 fBevelWidth = SkMaxScalar(1.0f, fBevelWidth); | |
223 | |
224 this->inval(nullptr); | |
225 return true; | |
226 } | |
robertphillips
2016/08/18 14:40:41
should there be and else here ?
dvonbeck
2016/08/18 15:12:14
Done.
| |
227 | |
228 // Moving light | |
229 if (nullptr == fSelectedCtrlRect) { | |
230 if (dx != 0 || dy != 0) { | |
231 float recipX = 1.0f / kAppWidth; | |
232 float recipY = 1.0f / kAppHeight; | |
233 | |
234 if (0 == click->fModifierKeys) { // No modifier | |
235 fBlueLight = SkLights::Light::MakeDirectional(fBlueLight.col or(), | |
236 SkVector3::Make((kAppWidth/2.0f - x) * recipX * -3.0 f, | |
237 (kAppHeight/2.0f - y) * recipY * -3. 0f, | |
238 1.0f)); | |
239 } else if (1 == click->fModifierKeys) { // Shift key | |
240 fRedLight = SkLights::Light::MakeDirectional(fRedLight.color (), | |
241 SkVector3::Make((kAppWidth/2.0f - x) * recipX * -3.0 f, | |
242 (kAppHeight/2.0f - y) * recipY * -3. 0f, | |
243 1.0f)); | |
244 } | |
245 | |
246 SkLights::Builder builder; | |
247 builder.add(fRedLight); | |
248 builder.add(fBlueLight); | |
249 builder.add(SkLights::Light::MakeAmbient( | |
250 SkColor3f::Make(0.4f, 0.4f, 0.4f))); | |
251 fLights = builder.finish(); | |
252 | |
253 this->inval(nullptr); | |
254 } | |
255 return true; | |
256 } | |
257 | |
258 return true; | |
259 } | |
260 | |
261 private: | |
262 static constexpr int kNumTestRects = 3; | |
263 | |
264 static constexpr SkScalar kAppWidth = 400.0f; | |
265 static constexpr SkScalar kAppHeight = 400.0f; | |
266 static constexpr SkScalar kShapeBoundsSize = 120.0f; | |
267 | |
268 static constexpr SkScalar kCtrlRange = 150.0f; | |
269 static constexpr SkScalar kBevelWidthMax = kShapeBoundsSize; | |
270 static constexpr SkScalar kBevelHeightMax = 50.0f; | |
271 static constexpr int kBevelTypeCount = 3; | |
272 | |
273 static constexpr SkScalar kSliderHeight = 20.0f; | |
274 static constexpr SkScalar kSliderWidth = 10.0f; | |
275 | |
276 const SkRect fShapeBounds; | |
277 | |
278 static constexpr int kNumControls = 3; | |
279 SkRect fCtrlRangeRects[kNumControls]; | |
280 SkRect* fSelectedCtrlRect; | |
281 SkRect fWidthCtrlRect; | |
282 SkRect fHeightCtrlRect; | |
283 SkRect fTypeCtrlRect; | |
284 | |
285 SkScalar fBevelWidth; | |
286 SkScalar fBevelHeight; | |
287 SkNormalSource::BevelType fBevelType; | |
288 | |
289 sk_sp<SkLights> fLights; | |
290 SkLights::Light fRedLight; | |
291 SkLights::Light fBlueLight; | |
292 | |
293 typedef SampleView INHERITED; | |
294 }; | |
295 | |
296 ////////////////////////////////////////////////////////////////////////////// | |
297 | |
298 static SkView* MyFactory() { return new BevelView; } | |
299 static SkViewRegister reg(MyFactory); | |
300 | |
OLD | NEW |