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

Side by Side Diff: samplecode/SampleLitAtlas.cpp

Issue 2026393005: Add SampleApp slide with animating lightmapped objects & transparency (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address code review comments Created 4 years, 6 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 | « include/core/SkLights.h ('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 * 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 "SkAnimTimer.h"
10 #include "SkView.h"
11 #include "SkCanvas.h"
12 #include "SkDrawable.h"
13 #include "SkLightingShader.h"
14 #include "SkLights.h"
15 #include "SkRandom.h"
16 #include "SkRSXform.h"
17
18 #include "sk_tool_utils.h"
19
20 class DrawLitAtlasDrawable : public SkDrawable {
21 public:
22 DrawLitAtlasDrawable(const SkRect& r)
23 : fBounds(r)
24 , fUseColors(false) {
25 fAtlas = MakeAtlas();
26
27 SkRandom rand;
28 for (int i = 0; i < kNumAsteroids; ++i) {
29 fAsteroids[i].initAsteroid(&rand, fBounds, &fDiffTex[i], &fNormTex[i ]);
30 }
31
32 fShip.initShip(fBounds, &fDiffTex[kNumAsteroids], &fNormTex[kNumAsteroid s]);
33
34 SkLights::Builder builder;
35
36 builder.add(SkLights::Light(SkColor3f::Make(1.0f, 1.0f, 1.0f),
37 SkVector3::Make(1.0f, 0.0f, 0.0f)));
38 builder.add(SkLights::Light(SkColor3f::Make(0.2f, 0.2f, 0.2f)));
39
40 fLights = builder.finish();
41 }
42
43 void toggleUseColors() {
44 fUseColors = !fUseColors;
45 }
46
47 void left() {
48 SkScalar newRot = SkScalarMod(fShip.rot() + (2*SK_ScalarPI - SK_ScalarPI /32.0f),
49 2 * SK_ScalarPI);
50 fShip.setRot(newRot);
51 }
52
53 void right() {
54 SkScalar newRot = SkScalarMod(fShip.rot() + SK_ScalarPI/32.0f, 2 * SK_Sc alarPI);
55 fShip.setRot(newRot);
56 }
57
58 void thrust() {
59 SkScalar c;
60 SkScalar s = SkScalarSinCos(fShip.rot(), &c);
61
62 SkVector newVel = fShip.velocity();
63 newVel.fX += s;
64 newVel.fY += -c;
65
66 if (newVel.lengthSqd() > kMaxShipSpeed*kMaxShipSpeed) {
67 newVel.setLength(SkIntToScalar(kMaxShipSpeed));
68 }
69
70 fShip.setVelocity(newVel);
71 }
72
73 protected:
74 void onDraw(SkCanvas* canvas) override {
75 SkRSXform xforms[kNumAsteroids+kNumShips];
76 SkColor colors[kNumAsteroids+kNumShips];
77
78 for (int i = 0; i < kNumAsteroids; ++i) {
79 fAsteroids[i].advance(fBounds);
80 xforms[i] = fAsteroids[i].asRSXform();
81 if (fUseColors) {
82 colors[i] = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF);
83 }
84 }
85
86 fShip.advance(fBounds);
87 xforms[kNumAsteroids] = fShip.asRSXform();
88 if (fUseColors) {
89 colors[kNumAsteroids] = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF);
90 }
91
92 #ifdef SK_DEBUG
93 canvas->drawBitmap(fAtlas, 0, 0); // just to see the atlas
94 #endif
95
96 #if 0
97 // TODO: revitalize when drawLitAtlas API lands
98 SkPaint paint;
99 paint.setFilterQuality(kLow_SkFilterQuality);
100
101 const SkRect cull = this->getBounds();
102 const SkColor* colorsPtr = fUseColors ? colors : NULL;
103
104 canvas->drawLitAtlas(fAtlas, xforms, fDiffTex, fNormTex, colorsPtr, kNum Asteroids+1,
105 SkXfermode::kModulate_Mode, &cull, &paint, fLights) ;
106 #else
107 SkMatrix diffMat, normalMat;
108
109 for (int i = 0; i < kNumAsteroids+1; ++i) {
110 colors[i] = colors[i] & 0xFF000000; // to silence compilers
111 SkPaint paint;
112
113 SkRect r = fDiffTex[i];
114 r.offsetTo(0, 0);
115
116 diffMat.setRectToRect(fDiffTex[i], r, SkMatrix::kFill_ScaleToFit);
117 normalMat.setRectToRect(fNormTex[i], r, SkMatrix::kFill_ScaleToFit);
118
119 SkMatrix m;
120 m.setRSXform(xforms[i]);
121
122 // TODO: correctly pull out the pure rotation
123 SkVector invNormRotation = { m[SkMatrix::kMScaleX], m[SkMatrix::kMSk ewY] };
124
125 paint.setShader(SkLightingShader::Make(fAtlas, fAtlas, fLights,
126 invNormRotation, &diffMat, &n ormalMat));
127
128 canvas->save();
129 canvas->setMatrix(m);
130 canvas->drawRect(r, paint);
131 canvas->restore();
132 }
133 #endif
134
135 #ifdef SK_DEBUG
136 {
137 SkPaint paint;
138 paint.setColor(SK_ColorRED);
139
140 for (int i = 0; i < kNumAsteroids; ++i) {
141 canvas->drawCircle(fAsteroids[i].pos().x(), fAsteroids[i].pos(). y(), 2, paint);
142 }
143 canvas->drawCircle(fShip.pos().x(), fShip.pos().y(), 2, paint);
144
145 paint.setStyle(SkPaint::kStroke_Style);
146 canvas->drawRect(this->getBounds(), paint);
147 }
148 #endif
149 }
150
151 SkRect onGetBounds() override {
152 return fBounds;
153 }
154
155 private:
156
157 enum ObjType {
158 kBigAsteroid_ObjType = 0,
159 kMedAsteroid_ObjType,
160 kSmAsteroid_ObjType,
161 kShip_ObjType,
162
163 kLast_ObjType = kShip_ObjType
164 };
165
166 static const int kObjTypeCount = kLast_ObjType + 1;
167
168 // Create the mixed diffuse & normal atlas
169 //
170 // big color circle | big normal hemi
171 // ------------------------------------
172 // med color circle | med normal pyra
173 // ------------------------------------
174 // sm color circle | sm normal hemi
175 // ------------------------------------
176 // big ship | big tetra normal
177 static SkBitmap MakeAtlas() {
178
179 SkBitmap atlas;
180 atlas.allocN32Pixels(kAtlasWidth, kAtlasHeight);
181
182 for (int y = 0; y < kAtlasHeight; ++y) {
183 int x = 0;
184 for ( ; x < kBigSize+kPad; ++x) {
185 *atlas.getAddr32(x, y) = SK_ColorTRANSPARENT;
186 }
187 for ( ; x < kAtlasWidth; ++x) {
188 *atlas.getAddr32(x, y) = SkPackARGB32(0xFF, 0x88, 0x88, 0xFF);
189 }
190 }
191
192 // big asteroid
193 {
194 SkPoint bigCenter = SkPoint::Make(kDiffXOff + kBigSize/2.0f, kBigYOf f + kBigSize/2.0f);
195
196 for (int y = kBigYOff; y < kBigYOff+kBigSize; ++y) {
197 for (int x = kDiffXOff; x < kDiffXOff+kBigSize; ++x) {
198 SkScalar distSq = (x - bigCenter.fX) * (x - bigCenter.fX) +
199 (y - bigCenter.fY) * (y - bigCenter.fY);
200 if (distSq > kBigSize*kBigSize/4.0f) {
201 *atlas.getAddr32(x, y) = SkPreMultiplyARGB(0, 0, 0, 0);
202 } else {
203 *atlas.getAddr32(x, y) = SkPackARGB32(0xFF, 0xFF, 0, 0);
204 }
205 }
206 }
207
208 sk_tool_utils::create_hemi_normal_map(&atlas,
209 SkIRect::MakeXYWH(kNormXOff, k BigYOff,
210 kBigSize, kB igSize));
211 }
212
213 // medium asteroid
214 {
215 for (int y = kMedYOff; y < kMedYOff+kMedSize; ++y) {
216 for (int x = kDiffXOff; x < kDiffXOff+kMedSize; ++x) {
217 *atlas.getAddr32(x, y) = SkPackARGB32(0xFF, 0, 0xFF, 0);
218 }
219 }
220
221 sk_tool_utils::create_frustum_normal_map(&atlas,
222 SkIRect::MakeXYWH(kNormXOff , kMedYOff,
223 kMedSize, kMedSize));
224 }
225
226 // small asteroid
227 {
228 SkPoint smCenter = SkPoint::Make(kDiffXOff + kSmSize/2.0f, kSmYOff + kSmSize/2.0f);
229
230 for (int y = kSmYOff; y < kSmYOff+kSmSize; ++y) {
231 for (int x = kDiffXOff; x < kDiffXOff+kSmSize; ++x) {
232 SkScalar distSq = (x - smCenter.fX) * (x - smCenter.fX) +
233 (y - smCenter.fY) * (y - smCenter.fY);
234 if (distSq > kSmSize*kSmSize/4.0f) {
235 *atlas.getAddr32(x, y) = SkPreMultiplyARGB(0, 0, 0, 0);
236 } else {
237 *atlas.getAddr32(x, y) = SkPackARGB32(0xFF, 0, 0, 0xFF);
238 }
239 }
240 }
241
242 sk_tool_utils::create_hemi_normal_map(&atlas,
243 SkIRect::MakeXYWH(kNormXOff, k SmYOff,
244 kSmSize, kSm Size));
245 }
246
247 // ship
248 {
249 SkScalar shipMidLine = kDiffXOff + kMedSize/2.0f;
250
251 for (int y = kShipYOff; y < kShipYOff+kMedSize; ++y) {
252 SkScalar scaledY = (y - kShipYOff)/(float)kMedSize; // 0..1
253
254 for (int x = kDiffXOff; x < kDiffXOff+kMedSize; ++x) {
255 SkScalar scaledX;
256
257 if (x < shipMidLine) {
258 scaledX = 1.0f - (x - kDiffXOff)/(kMedSize/2.0f); // 0.. 1
259 } else {
260 scaledX = (x - shipMidLine)/(kMedSize/2.0f); // 0.. 1
261 }
262
263 if (scaledX < scaledY) {
264 *atlas.getAddr32(x, y) = SkPackARGB32(0xFF, 0, 0xFF, 0xF F);
265 } else {
266 *atlas.getAddr32(x, y) = SkPackARGB32(0, 0, 0, 0);
267 }
268 }
269 }
270
271 sk_tool_utils::create_tetra_normal_map(&atlas,
272 SkIRect::MakeXYWH(kNormXOff, kShipYOff,
273 kMedSize, k MedSize));
274 }
275
276 return atlas;
277 }
278
279 class ObjectRecord {
280 public:
281 void initAsteroid(SkRandom *rand, const SkRect& bounds,
282 SkRect* diffTex, SkRect* normTex) {
283 static const SkScalar gMaxSpeeds[3] = { 1, 2, 5 }; // smaller astero ids can go faster
284 static const SkScalar gYOffs[3] = { kBigYOff, kMedYOff, kSmYOff };
285 static const SkScalar gSizes[3] = { kBigSize, kMedSize, kSmSize };
286
287 static unsigned int asteroidType = 0;
288 fObjType = static_cast<ObjType>(asteroidType++ % 3);
289
290 fPosition.set(bounds.fLeft + rand->nextUScalar1() * bounds.width(),
291 bounds.fTop + rand->nextUScalar1() * bounds.height());
292 fVelocity.fX = rand->nextSScalar1();
293 fVelocity.fY = sqrt(1.0f - fVelocity.fX * fVelocity.fX);
294 SkASSERT(SkScalarNearlyEqual(fVelocity.length(), 1.0f));
295 fVelocity *= gMaxSpeeds[fObjType];
296 fRot = 0;
297 fDeltaRot = rand->nextSScalar1() / 32;
298
299 diffTex->setXYWH(SkIntToScalar(kDiffXOff), gYOffs[fObjType],
300 gSizes[fObjType], gSizes[fObjType]);
301 normTex->setXYWH(SkIntToScalar(kNormXOff), gYOffs[fObjType],
302 gSizes[fObjType], gSizes[fObjType]);
303 }
304
305 void initShip(const SkRect& bounds, SkRect* diffTex, SkRect* normTex) {
306 fObjType = kShip_ObjType;
307 fPosition.set(bounds.centerX(), bounds.centerY());
308 fVelocity = SkVector::Make(0.0f, 0.0f);
309 fRot = 0.0f;
310 fDeltaRot = 0.0f;
311
312 diffTex->setXYWH(SkIntToScalar(kDiffXOff), SkIntToScalar(kShipYOff),
313 SkIntToScalar(kMedSize), SkIntToScalar(kMedSize));
314 normTex->setXYWH(SkIntToScalar(kNormXOff), SkIntToScalar(kShipYOff),
315 SkIntToScalar(kMedSize), SkIntToScalar(kMedSize));
316 }
317
318 void advance(const SkRect& bounds) {
319 fPosition += fVelocity;
320 if (fPosition.fX > bounds.right()) {
321 SkASSERT(fVelocity.fX > 0);
322 fVelocity.fX = -fVelocity.fX;
323 } else if (fPosition.fX < bounds.left()) {
324 SkASSERT(fVelocity.fX < 0);
325 fVelocity.fX = -fVelocity.fX;
326 }
327 if (fPosition.fY > bounds.bottom()) {
328 if (fVelocity.fY > 0) {
329 fVelocity.fY = -fVelocity.fY;
330 }
331 } else if (fPosition.fY < bounds.top()) {
332 if (fVelocity.fY < 0) {
333 fVelocity.fY = -fVelocity.fY;
334 }
335 }
336
337 fRot += fDeltaRot;
338 fRot = SkScalarMod(fRot, 2 * SK_ScalarPI);
339 }
340
341 const SkPoint& pos() const { return fPosition; }
342
343 SkScalar rot() const { return fRot; }
344 void setRot(SkScalar rot) { fRot = rot; }
345
346 const SkPoint& velocity() const { return fVelocity; }
347 void setVelocity(const SkPoint& velocity) { fVelocity = velocity; }
348
349 SkRSXform asRSXform() const {
350 static const SkScalar gHalfSizes[kObjTypeCount] = {
351 SkScalarHalf(kBigSize),
352 SkScalarHalf(kMedSize),
353 SkScalarHalf(kSmSize),
354 SkScalarHalf(kMedSize),
355 };
356
357 return SkRSXform::MakeFromRadians(1.0f, fRot, fPosition.x(), fPositi on.y(),
358 gHalfSizes[fObjType],
359 gHalfSizes[fObjType]);
360 }
361
362 private:
363 ObjType fObjType;
364 SkPoint fPosition;
365 SkVector fVelocity;
366 SkScalar fRot; // In radians.
367 SkScalar fDeltaRot; // In radiands. Not used by ship.
368 };
369
370
371
372
373 private:
374 static const int kNumLights = 2;
375 static const int kNumAsteroids = 6;
376 static const int kNumShips = 1;
377
378 static const int kBigSize = 128;
379 static const int kMedSize = 64;
380 static const int kSmSize = 32;
381 static const int kPad = 1;
382 static const int kAtlasWidth = kBigSize + kBigSize + 2 * kPad; // 2 pads in the middle
383 static const int kAtlasHeight = kBigSize + kMedSize + kSmSize + kMedSize + 3 * kPad;
384
385 static const int kDiffXOff = 0;
386 static const int kNormXOff = kBigSize + 2 * kPad;
387
388 static const int kBigYOff = 0;
389 static const int kMedYOff = kBigSize + kPad;
390 static const int kSmYOff = kMedYOff + kMedSize + kPad;
391 static const int kShipYOff = kSmYOff + kSmSize + kPad;
392 static const int kMaxShipSpeed = 5;
393
394 SkBitmap fAtlas;
395 ObjectRecord fAsteroids[kNumAsteroids];
396 ObjectRecord fShip;
397 SkRect fDiffTex[kNumAsteroids+kNumShips];
398 SkRect fNormTex[kNumAsteroids+kNumShips];
399 SkRect fBounds;
400 bool fUseColors;
401 sk_sp<SkLights> fLights;
402
403 typedef SkDrawable INHERITED;
404 };
405
406 class DrawLitAtlasView : public SampleView {
407 public:
408 DrawLitAtlasView()
409 : fDrawable(new DrawLitAtlasDrawable(SkRect::MakeWH(640, 480))) {
410 }
411
412 protected:
413 bool onQuery(SkEvent* evt) override {
414 if (SampleCode::TitleQ(*evt)) {
415 SampleCode::TitleR(evt, "DrawLitAtlas");
416 return true;
417 }
418 SkUnichar uni;
419 if (SampleCode::CharQ(*evt, &uni)) {
420 switch (uni) {
421 case 'C':
422 fDrawable->toggleUseColors();
423 this->inval(NULL);
424 return true;
425 case 'j':
426 fDrawable->left();
427 this->inval(NULL);
428 return true;
429 case 'k':
430 fDrawable->thrust();
431 this->inval(NULL);
432 return true;
433 case 'l':
434 fDrawable->right();
435 this->inval(NULL);
436 return true;
437 default:
438 break;
439 }
440 }
441 return this->INHERITED::onQuery(evt);
442 }
443
444 void onDrawContent(SkCanvas* canvas) override {
445 canvas->drawDrawable(fDrawable);
446 this->inval(NULL);
447 }
448
449 #if 0
450 // TODO: switch over to use this for our animation
451 bool onAnimate(const SkAnimTimer& timer) override {
452 SkScalar angle = SkDoubleToScalar(fmod(timer.secs() * 360 / 24, 360));
453 fAnimatingDrawable->setSweep(angle);
454 return true;
455 }
456 #endif
457
458 private:
459 SkAutoTUnref<DrawLitAtlasDrawable> fDrawable;
460
461 typedef SampleView INHERITED;
462 };
463
464 //////////////////////////////////////////////////////////////////////////////
465
466 static SkView* MyFactory() { return new DrawLitAtlasView; }
467 static SkViewRegister reg(MyFactory);
OLDNEW
« no previous file with comments | « include/core/SkLights.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698