SampleApp.cpp revision 4417740a480786ca65379ba5b398c500ba34ee18
1#include "SkCanvas.h" 2#include "SkDevice.h" 3#include "SkGLCanvas.h" 4#include "SkGraphics.h" 5#include "SkImageEncoder.h" 6#include "SkPaint.h" 7#include "SkPicture.h" 8#include "SkStream.h" 9#include "SkTime.h" 10#include "SkWindow.h" 11 12#include "SampleCode.h" 13 14SkView* create_overview(int, const SkViewFactory*); 15 16//#define SK_SUPPORT_GL 17 18#ifdef SK_SUPPORT_GL 19#include <AGL/agl.h> 20#include <OpenGL/gl.h> 21#endif 22 23#define ANIMATING_EVENTTYPE "nextSample" 24#define ANIMATING_DELAY 750 25 26#define USE_OFFSCREEN 27 28SkViewRegister* SkViewRegister::gHead; 29SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) { 30 static bool gOnce; 31 if (!gOnce) { 32 gHead = NULL; 33 gOnce = true; 34 } 35 36 fChain = gHead; 37 gHead = this; 38} 39 40#ifdef SK_SUPPORT_GL 41static AGLContext gAGLContext; 42 43static void init_gl(WindowRef wref) { 44 GLint major, minor; 45 46 aglGetVersion(&major, &minor); 47 SkDebugf("---- agl version %d %d\n", major, minor); 48 49 const GLint pixelAttrs[] = { 50 AGL_RGBA, 51 AGL_DEPTH_SIZE, 32, 52 AGL_OFFSCREEN, 53 AGL_NONE 54 }; 55 56 AGLPixelFormat format = aglCreatePixelFormat(pixelAttrs); 57 SkDebugf("----- agl format %p\n", format); 58 gAGLContext = aglCreateContext(format, NULL); 59 SkDebugf("----- agl context %p\n", gAGLContext); 60 aglDestroyPixelFormat(format); 61 62 aglEnable(gAGLContext, GL_BLEND); 63 aglEnable(gAGLContext, GL_LINE_SMOOTH); 64 aglEnable(gAGLContext, GL_POINT_SMOOTH); 65 aglEnable(gAGLContext, GL_POLYGON_SMOOTH); 66 67 aglSetCurrentContext(gAGLContext); 68} 69 70static void setup_offscreen_gl(const SkBitmap& offscreen, WindowRef wref) { 71 GLboolean success = true; 72 73#ifdef USE_OFFSCREEN 74 success = aglSetOffScreen(gAGLContext, 75 offscreen.width(), 76 offscreen.height(), 77 offscreen.rowBytes(), 78 offscreen.getPixels()); 79#else 80 success = aglSetWindowRef(gAGLContext, wref); 81#endif 82 83 GLenum err = aglGetError(); 84 if (err) { 85 SkDebugf("---- setoffscreen %d %d %s [%d %d]\n", success, err, 86 aglErrorString(err), offscreen.width(), offscreen.height()); 87 } 88 89 glEnable(GL_BLEND); 90 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 91 glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); 92 glEnable(GL_TEXTURE_2D); 93 94 glClearColor(0, 0, 0, 0); 95 glClear(GL_COLOR_BUFFER_BIT); 96} 97#endif 98 99////////////////////////////////////////////////////////////////////////////// 100 101static const char gTitleEvtName[] = "SampleCode_Title_Event"; 102static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event"; 103 104bool SampleCode::TitleQ(const SkEvent& evt) { 105 return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1); 106} 107 108void SampleCode::TitleR(SkEvent* evt, const char title[]) { 109 SkASSERT(evt && TitleQ(*evt)); 110 evt->setString(gTitleEvtName, title); 111} 112 113bool SampleCode::PrefSizeQ(const SkEvent& evt) { 114 return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1); 115} 116 117void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) { 118 SkASSERT(evt && PrefSizeQ(*evt)); 119 SkScalar size[2]; 120 size[0] = width; 121 size[1] = height; 122 evt->setScalars(gPrefSizeEvtName, 2, size); 123} 124 125static SkMSec gAnimTime; 126SkMSec SampleCode::GetAnimTime() { return gAnimTime; } 127 128SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) { 129 SkScalar seconds = SkFloatToScalar(gAnimTime / 1000.0f); 130 SkScalar value = SkScalarMul(speed, seconds); 131 if (period) { 132 value = SkScalarMod(value, period); 133 } 134 return value; 135} 136 137////////////////////////////////////////////////////////////////////////////// 138 139class SampleWindow : public SkOSWindow { 140 SkTDArray<SkViewFactory> fSamples; 141public: 142 SampleWindow(void* hwnd); 143 virtual ~SampleWindow(); 144 145 virtual void draw(SkCanvas* canvas); 146 147protected: 148 virtual void onDraw(SkCanvas* canvas); 149 virtual bool onHandleKey(SkKey key); 150 virtual bool onHandleChar(SkUnichar); 151 virtual void onSizeChange(); 152 153 virtual SkCanvas* beforeChildren(SkCanvas*); 154 virtual void afterChildren(SkCanvas*); 155 virtual void beforeChild(SkView* child, SkCanvas* canvas); 156 virtual void afterChild(SkView* child, SkCanvas* canvas); 157 158 virtual bool onEvent(const SkEvent& evt); 159 160#if 0 161 virtual bool handleChar(SkUnichar uni); 162 virtual bool handleEvent(const SkEvent& evt); 163 virtual bool handleKey(SkKey key); 164 virtual bool handleKeyUp(SkKey key); 165 166 virtual bool onClick(Click* click); 167 virtual Click* onFindClickHandler(SkScalar x, SkScalar y); 168 virtual bool onHandleKeyUp(SkKey key); 169#endif 170private: 171 int fCurrIndex; 172 173 SkPicture* fPicture; 174 SkGLCanvas* fGLCanvas; 175 SkPath fClipPath; 176 177 enum CanvasType { 178 kRaster_CanvasType, 179 kPicture_CanvasType, 180 kOpenGL_CanvasType 181 }; 182 CanvasType fCanvasType; 183 184 bool fUseClip; 185 bool fNClip; 186 bool fRepeatDrawing; 187 bool fAnimating; 188 bool fRotate; 189 bool fScale; 190 191 int fScrollTestX, fScrollTestY; 192 193 void loadView(SkView*); 194 void updateTitle(); 195 bool nextSample(); 196 197 void postAnimatingEvent() { 198 if (fAnimating) { 199 SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE); 200 evt->post(this->getSinkID(), ANIMATING_DELAY); 201 } 202 } 203 204 205 static CanvasType cycle_canvastype(CanvasType); 206 207 typedef SkOSWindow INHERITED; 208}; 209 210SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) { 211 static const CanvasType gCT[] = { 212 kPicture_CanvasType, 213 kOpenGL_CanvasType, 214 kRaster_CanvasType 215 }; 216 return gCT[ct]; 217} 218 219SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) { 220#ifdef SK_SUPPORT_GL 221 init_gl((WindowRef)hwnd); 222#endif 223 224 fPicture = NULL; 225 fGLCanvas = NULL; 226 227 fCanvasType = kRaster_CanvasType; 228 fUseClip = false; 229 fNClip = false; 230 fRepeatDrawing = false; 231 fAnimating = false; 232 fRotate = false; 233 fScale = false; 234 235 fScrollTestX = fScrollTestY = 0; 236 237// this->setConfig(SkBitmap::kRGB_565_Config); 238 this->setConfig(SkBitmap::kARGB_8888_Config); 239 this->setVisibleP(true); 240 241 { 242 const SkViewRegister* reg = SkViewRegister::Head(); 243 while (reg) { 244 *fSamples.append() = reg->factory(); 245 reg = reg->next(); 246 } 247 } 248 fCurrIndex = 0; 249 this->loadView(fSamples[fCurrIndex]()); 250} 251 252SampleWindow::~SampleWindow() { 253 delete fPicture; 254 delete fGLCanvas; 255} 256 257#define XCLIP_N 8 258#define YCLIP_N 8 259 260void SampleWindow::draw(SkCanvas* canvas) { 261 // update the animation time 262 gAnimTime = SkTime::GetMSecs(); 263 264 if (fNClip) { 265 // this->INHERITED::draw(canvas); 266 // SkBitmap orig = capture_bitmap(canvas); 267 268 const SkScalar w = this->width(); 269 const SkScalar h = this->height(); 270 const SkScalar cw = w / XCLIP_N; 271 const SkScalar ch = h / YCLIP_N; 272 for (int y = 0; y < YCLIP_N; y++) { 273 for (int x = 0; x < XCLIP_N; x++) { 274 SkAutoCanvasRestore acr(canvas, true); 275 SkRect r = { 276 x * cw, y * ch, (x + 1) * cw, (y + 1) * ch 277 }; 278 canvas->clipRect(r); 279 this->INHERITED::draw(canvas); 280 } 281 } 282 } else { 283 this->INHERITED::draw(canvas); 284 } 285} 286 287void SampleWindow::onDraw(SkCanvas* canvas) { 288 if (fRepeatDrawing) { 289 this->inval(NULL); 290 } 291} 292 293#include "SkColorPriv.h" 294 295static void reverseRedAndBlue(const SkBitmap& bm) { 296 SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config); 297 uint8_t* p = (uint8_t*)bm.getPixels(); 298 uint8_t* stop = p + bm.getSize(); 299 while (p < stop) { 300 // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply 301 unsigned scale = SkAlpha255To256(p[3]); 302 unsigned r = p[2]; 303 unsigned b = p[0]; 304 p[0] = SkAlphaMul(r, scale); 305 p[1] = SkAlphaMul(p[1], scale); 306 p[2] = SkAlphaMul(b, scale); 307 p += 4; 308 } 309} 310 311SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) { 312#ifdef SK_SUPPORT_GL 313#ifndef USE_OFFSCREEN 314 aglSetWindowRef(gAGLContext, NULL); 315#endif 316#endif 317 switch (fCanvasType) { 318 case kRaster_CanvasType: 319 canvas = this->INHERITED::beforeChildren(canvas); 320 break; 321 case kPicture_CanvasType: 322 fPicture = new SkPicture; 323 canvas = fPicture->beginRecording(9999, 9999); 324 break; 325#ifdef SK_SUPPORT_GL 326 case kOpenGL_CanvasType: { 327 //SkGLCanvas::DeleteAllTextures(); // just for testing 328 SkDevice* device = canvas->getDevice(); 329 const SkBitmap& bitmap = device->accessBitmap(true); 330 // first clear the raster bitmap, so we don't see any leftover bits 331 bitmap.eraseColor(0); 332 // now setup our glcanvas 333 setup_offscreen_gl(bitmap, (WindowRef)this->getHWND()); 334 fGLCanvas = new SkGLCanvas; 335 fGLCanvas->setViewport(bitmap.width(), bitmap.height()); 336 canvas = fGLCanvas; 337 break; 338 } 339#endif 340 } 341 342 if (fUseClip) { 343 canvas->drawColor(0xFFFF88FF); 344 canvas->clipPath(fClipPath); 345 } 346 347 return canvas; 348} 349 350static void paint_rgn(const SkBitmap& bm, const SkIRect& r, 351 const SkRegion& rgn) { 352 SkCanvas canvas(bm); 353 SkRegion inval(rgn); 354 355 inval.translate(r.fLeft, r.fTop); 356 canvas.clipRegion(inval); 357 canvas.drawColor(0xFFFF8080); 358} 359 360void SampleWindow::afterChildren(SkCanvas* orig) { 361 switch (fCanvasType) { 362 case kRaster_CanvasType: 363 break; 364 case kPicture_CanvasType: 365 if (true) { 366 SkPicture* pict = new SkPicture(*fPicture); 367 fPicture->unref(); 368 orig->drawPicture(*pict); 369 pict->unref(); 370 } else if (true) { 371 SkDynamicMemoryWStream ostream; 372 fPicture->serialize(&ostream); 373 fPicture->unref(); 374 375 SkMemoryStream istream(ostream.getStream(), ostream.getOffset()); 376 SkPicture pict(&istream); 377 orig->drawPicture(pict); 378 } else { 379 fPicture->draw(orig); 380 fPicture->unref(); 381 } 382 fPicture = NULL; 383 break; 384#ifdef SK_SUPPORT_GL 385 case kOpenGL_CanvasType: 386 glFlush(); 387 delete fGLCanvas; 388 fGLCanvas = NULL; 389#ifdef USE_OFFSCREEN 390 reverseRedAndBlue(orig->getDevice()->accessBitmap(true)); 391#endif 392 break; 393#endif 394 } 395 396// if ((fScrollTestX | fScrollTestY) != 0) 397 { 398 const SkBitmap& bm = orig->getDevice()->accessBitmap(true); 399 int dx = fScrollTestX * 7; 400 int dy = fScrollTestY * 7; 401 SkIRect r; 402 SkRegion inval; 403 404 r.set(50, 50, 50+100, 50+100); 405 bm.scrollRect(&r, dx, dy, &inval); 406 paint_rgn(bm, r, inval); 407 } 408} 409 410void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) { 411 if (fScale) { 412 SkScalar scale = SK_Scalar1 * 7 / 10; 413 SkScalar cx = this->width() / 2; 414 SkScalar cy = this->height() / 2; 415 canvas->translate(cx, cy); 416 canvas->scale(scale, scale); 417 canvas->translate(-cx, -cy); 418 } 419 if (fRotate) { 420 SkScalar cx = this->width() / 2; 421 SkScalar cy = this->height() / 2; 422 canvas->translate(cx, cy); 423 canvas->rotate(SkIntToScalar(30)); 424 canvas->translate(-cx, -cy); 425 } 426} 427 428void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) { 429} 430 431static SkBitmap::Config gConfigCycle[] = { 432 SkBitmap::kNo_Config, // none -> none 433 SkBitmap::kNo_Config, // a1 -> none 434 SkBitmap::kNo_Config, // a8 -> none 435 SkBitmap::kNo_Config, // index8 -> none 436 SkBitmap::kARGB_4444_Config, // 565 -> 4444 437 SkBitmap::kARGB_8888_Config, // 4444 -> 8888 438 SkBitmap::kRGB_565_Config // 8888 -> 565 439}; 440 441static SkBitmap::Config cycle_configs(SkBitmap::Config c) { 442 return gConfigCycle[c]; 443} 444 445bool SampleWindow::nextSample() { 446 fCurrIndex = (fCurrIndex + 1) % fSamples.count(); 447 this->loadView(fSamples[fCurrIndex]()); 448 return true; 449} 450 451bool SampleWindow::onEvent(const SkEvent& evt) { 452 if (evt.isType(ANIMATING_EVENTTYPE)) { 453 if (fAnimating) { 454 this->nextSample(); 455 this->postAnimatingEvent(); 456 } 457 return true; 458 } 459 if (evt.isType("set-curr-index")) { 460 fCurrIndex = evt.getFast32() % fSamples.count(); 461 this->loadView(fSamples[fCurrIndex]()); 462 return true; 463 } 464 return this->INHERITED::onEvent(evt); 465} 466 467static void cleanup_for_filename(SkString* name) { 468 char* str = name->writable_str(); 469 for (int i = 0; i < name->size(); i++) { 470 switch (str[i]) { 471 case ':': str[i] = '-'; break; 472 case '/': str[i] = '-'; break; 473 case ' ': str[i] = '_'; break; 474 default: break; 475 } 476 } 477} 478 479bool SampleWindow::onHandleChar(SkUnichar uni) { 480 int dx = 0xFF; 481 int dy = 0xFF; 482 483 switch (uni) { 484 case '5': dx = 0; dy = 0; break; 485 case '8': dx = 0; dy = -1; break; 486 case '6': dx = 1; dy = 0; break; 487 case '2': dx = 0; dy = 1; break; 488 case '4': dx = -1; dy = 0; break; 489 case '7': dx = -1; dy = -1; break; 490 case '9': dx = 1; dy = -1; break; 491 case '3': dx = 1; dy = 1; break; 492 case '1': dx = -1; dy = 1; break; 493 494 default: 495 break; 496 } 497 498 if (0xFF != dx && 0xFF != dy) { 499 if ((dx | dy) == 0) { 500 fScrollTestX = fScrollTestY = 0; 501 } else { 502 fScrollTestX += dx; 503 fScrollTestY += dy; 504 } 505 this->inval(NULL); 506 return true; 507 } 508 509 switch (uni) { 510 case 'a': 511 fAnimating = !fAnimating; 512 this->postAnimatingEvent(); 513 this->updateTitle(); 514 return true; 515 case 'f': { 516 const char* title = this->getTitle(); 517 if (title[0] == 0) { 518 title = "sampleapp"; 519 } 520 SkString name(title); 521 cleanup_for_filename(&name); 522 name.append(".png"); 523 if (SkImageEncoder::EncodeFile(name.c_str(), this->getBitmap(), 524 SkImageEncoder::kPNG_Type, 100)) { 525 SkDebugf("Created %s\n", name.c_str()); 526 } 527 return true; 528 } 529 case 'r': 530 fRotate = !fRotate; 531 this->inval(NULL); 532 this->updateTitle(); 533 return true; 534 case 's': 535 fScale = !fScale; 536 this->inval(NULL); 537 this->updateTitle(); 538 return true; 539 default: 540 break; 541 } 542 543 return this->INHERITED::onHandleChar(uni); 544} 545 546#include "SkDumpCanvas.h" 547 548bool SampleWindow::onHandleKey(SkKey key) { 549 switch (key) { 550 case kRight_SkKey: 551 if (this->nextSample()) { 552 return true; 553 } 554 break; 555 case kLeft_SkKey: 556 fCanvasType = cycle_canvastype(fCanvasType); 557 this->updateTitle(); 558 this->inval(NULL); 559 return true; 560 case kUp_SkKey: 561 fNClip = !fNClip; 562 this->updateTitle(); 563 this->inval(NULL); 564 return true; 565 case kDown_SkKey: 566 this->setConfig(cycle_configs(this->getBitmap().config())); 567 this->updateTitle(); 568 return true; 569 case kOK_SkKey: 570 if (true) { 571 SkDebugfDumper dumper; 572 SkDumpCanvas dc(&dumper); 573 this->draw(&dc); 574 } else { 575 fRepeatDrawing = !fRepeatDrawing; 576 if (fRepeatDrawing) { 577 this->inval(NULL); 578 } 579 } 580 return true; 581 case kBack_SkKey: 582 this->loadView(NULL); 583 return true; 584 default: 585 break; 586 } 587 return this->INHERITED::onHandleKey(key); 588} 589 590void SampleWindow::loadView(SkView* view) { 591 SkView::F2BIter iter(this); 592 SkView* prev = iter.next(); 593 if (prev) { 594 prev->detachFromParent(); 595 } 596 597 if (NULL == view) { 598 view = create_overview(fSamples.count(), fSamples.begin()); 599 } 600 view->setVisibleP(true); 601 this->attachChildToFront(view)->unref(); 602 view->setSize(this->width(), this->height()); 603 604 this->updateTitle(); 605} 606 607static const char* gConfigNames[] = { 608 "unknown config", 609 "A1", 610 "A8", 611 "Index8", 612 "565", 613 "4444", 614 "8888" 615}; 616 617static const char* configToString(SkBitmap::Config c) { 618 return gConfigNames[c]; 619} 620 621static const char* gCanvasTypePrefix[] = { 622 "raster: ", 623 "picture: ", 624 "opengl: " 625}; 626 627void SampleWindow::updateTitle() { 628 SkString title; 629 630 SkView::F2BIter iter(this); 631 SkView* view = iter.next(); 632 SkEvent evt(gTitleEvtName); 633 if (view->doQuery(&evt)) { 634 title.set(evt.findString(gTitleEvtName)); 635 } 636 if (title.size() == 0) { 637 title.set("<unknown>"); 638 } 639 640 title.prepend(gCanvasTypePrefix[fCanvasType]); 641 642 title.prepend(" "); 643 title.prepend(configToString(this->getBitmap().config())); 644 645 if (fAnimating) { 646 title.prepend("<A> "); 647 } 648 if (fScale) { 649 title.prepend("<S> "); 650 } 651 if (fRotate) { 652 title.prepend("<R> "); 653 } 654 if (fNClip) { 655 title.prepend("<C> "); 656 } 657 this->setTitle(title.c_str()); 658} 659 660void SampleWindow::onSizeChange() { 661 this->INHERITED::onSizeChange(); 662 663 SkView::F2BIter iter(this); 664 SkView* view = iter.next(); 665 view->setSize(this->width(), this->height()); 666 667 // rebuild our clippath 668 { 669 const SkScalar W = this->width(); 670 const SkScalar H = this->height(); 671 672 fClipPath.reset(); 673#if 0 674 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) { 675 SkRect r; 676 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30)); 677 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0)) 678 fClipPath.addRect(r); 679 } 680#else 681 SkRect r; 682 r.set(0, 0, W, H); 683 fClipPath.addRect(r, SkPath::kCCW_Direction); 684 r.set(W/4, H/4, W*3/4, H*3/4); 685 fClipPath.addRect(r, SkPath::kCW_Direction); 686#endif 687 } 688 689 this->updateTitle(); // to refresh our config 690} 691 692/////////////////////////////////////////////////////////////////////////////// 693 694SkOSWindow* create_sk_window(void* hwnd) { 695 return new SampleWindow(hwnd); 696} 697 698void get_preferred_size(int* x, int* y, int* width, int* height) { 699 *x = 10; 700 *y = 50; 701 *width = 640; 702 *height = 480; 703} 704 705void application_init() { 706// setenv("ANDROID_ROOT", "../../../data", 0); 707 setenv("ANDROID_ROOT", "/android/device/data", 0); 708 SkGraphics::Init(); 709 SkEvent::Init(); 710} 711 712void application_term() { 713 SkEvent::Term(); 714 SkGraphics::Term(); 715} 716