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