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