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