blob: df0723f3e19bbbf156d8e4f2d2a9ec7e3f152285 [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.com0ae6b242008-12-23 16:49:54 +00005#include "SkImageDecoder.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*);
137
138 virtual bool onEvent(const SkEvent& evt);
139
140#if 0
141 virtual bool handleChar(SkUnichar uni);
142 virtual bool handleEvent(const SkEvent& evt);
143 virtual bool handleKey(SkKey key);
144 virtual bool handleKeyUp(SkKey key);
145
146 virtual bool onClick(Click* click);
147 virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
148 virtual bool onHandleKeyUp(SkKey key);
149#endif
150private:
151 const SkViewRegister* fCurr;
152
153 SkPicture* fPicture;
154 SkGLCanvas* fGLCanvas;
155 SkPath fClipPath;
156
157 enum CanvasType {
158 kRaster_CanvasType,
159 kPicture_CanvasType,
160 kOpenGL_CanvasType
161 };
162 CanvasType fCanvasType;
163
164 bool fUseClip;
165 bool fRepeatDrawing;
166 bool fAnimating;
167
168 int fScrollTestX, fScrollTestY;
169
170 void loadView(SkView*);
171 void updateTitle();
172 bool nextSample();
173
174 void postAnimatingEvent() {
175 if (fAnimating) {
176 SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
177 evt->post(this->getSinkID(), ANIMATING_DELAY);
178 }
179 }
180
181
182 static CanvasType cycle_canvastype(CanvasType);
183
184 typedef SkOSWindow INHERITED;
185};
186
187SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
188 static const CanvasType gCT[] = {
189 kPicture_CanvasType,
190 kOpenGL_CanvasType,
191 kRaster_CanvasType
192 };
193 return gCT[ct];
194}
195
196SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
reed@android.com6efdc472008-12-19 18:24:35 +0000197#ifdef SK_SUPPORT_GL
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198 init_gl((WindowRef)hwnd);
reed@android.com6efdc472008-12-19 18:24:35 +0000199#endif
200
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201 fPicture = NULL;
202 fGLCanvas = NULL;
203
204 fCanvasType = kRaster_CanvasType;
205 fUseClip = false;
206 fRepeatDrawing = false;
207 fAnimating = false;
208
209 fScrollTestX = fScrollTestY = 0;
210
211// this->setConfig(SkBitmap::kRGB_565_Config);
212 this->setConfig(SkBitmap::kARGB_8888_Config);
213 this->setVisibleP(true);
214
215 fCurr = SkViewRegister::Head();
216 this->loadView(fCurr->factory()());
217}
218
219SampleWindow::~SampleWindow() {
220 delete fPicture;
221 delete fGLCanvas;
222}
223
224void SampleWindow::onDraw(SkCanvas* canvas) {
225 if (fRepeatDrawing) {
226 this->inval(NULL);
227 }
228}
229
230#include "SkColorPriv.h"
231
232static void reverseRedAndBlue(const SkBitmap& bm) {
233 SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
234 uint8_t* p = (uint8_t*)bm.getPixels();
235 uint8_t* stop = p + bm.getSize();
236 while (p < stop) {
237 // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
238 unsigned scale = SkAlpha255To256(p[3]);
239 unsigned r = p[2];
240 unsigned b = p[0];
241 p[0] = SkAlphaMul(r, scale);
242 p[1] = SkAlphaMul(p[1], scale);
243 p[2] = SkAlphaMul(b, scale);
244 p += 4;
245 }
246}
247
248SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
reed@android.com6efdc472008-12-19 18:24:35 +0000249#ifdef SK_SUPPORT_GL
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250#ifndef USE_OFFSCREEN
251 aglSetWindowRef(gAGLContext, NULL);
252#endif
reed@android.com6efdc472008-12-19 18:24:35 +0000253#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 switch (fCanvasType) {
255 case kRaster_CanvasType:
256 canvas = this->INHERITED::beforeChildren(canvas);
257 break;
258 case kPicture_CanvasType:
259 fPicture = new SkPicture;
260 canvas = fPicture->beginRecording(9999, 9999);
261 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000262#ifdef SK_SUPPORT_GL
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 case kOpenGL_CanvasType: {
264 //SkGLCanvas::DeleteAllTextures(); // just for testing
265 SkDevice* device = canvas->getDevice();
266 const SkBitmap& bitmap = device->accessBitmap(true);
267 // first clear the raster bitmap, so we don't see any leftover bits
268 bitmap.eraseColor(0);
269 // now setup our glcanvas
270 setup_offscreen_gl(bitmap, (WindowRef)this->getHWND());
271 fGLCanvas = new SkGLCanvas;
272 fGLCanvas->setViewport(bitmap.width(), bitmap.height());
273 canvas = fGLCanvas;
274 break;
275 }
reed@android.com6efdc472008-12-19 18:24:35 +0000276#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277 }
278
279 if (fUseClip) {
280 canvas->drawColor(0xFFFF88FF);
281 canvas->clipPath(fClipPath);
282 }
283
284 return canvas;
285}
286
287static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
288 const SkRegion& rgn) {
289 SkCanvas canvas(bm);
290 SkRegion inval(rgn);
291
292 inval.translate(r.fLeft, r.fTop);
293 canvas.clipRegion(inval);
294 canvas.drawColor(0xFFFF8080);
295}
296
297void SampleWindow::afterChildren(SkCanvas* orig) {
298 switch (fCanvasType) {
299 case kRaster_CanvasType:
300 break;
301 case kPicture_CanvasType:
302 if (false) {
303 SkPicture* pict = new SkPicture(*fPicture);
304 fPicture->unref();
305 orig->drawPicture(*pict);
306 pict->unref();
307 } if (true) {
308 SkDynamicMemoryWStream ostream;
309 fPicture->serialize(&ostream);
310 fPicture->unref();
311
312 SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
313 SkPicture pict(&istream);
314 orig->drawPicture(pict);
315 } else {
316 fPicture->draw(orig);
317 fPicture->unref();
318 }
319 fPicture = NULL;
320 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000321#ifdef SK_SUPPORT_GL
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322 case kOpenGL_CanvasType:
323 glFlush();
324 delete fGLCanvas;
325 fGLCanvas = NULL;
326#ifdef USE_OFFSCREEN
327 reverseRedAndBlue(orig->getDevice()->accessBitmap(true));
328#endif
329 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000330#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 }
332
333// if ((fScrollTestX | fScrollTestY) != 0)
334 {
335 const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
336 int dx = fScrollTestX * 7;
337 int dy = fScrollTestY * 7;
338 SkIRect r;
339 SkRegion inval;
340
341 r.set(50, 50, 50+100, 50+100);
342 bm.scrollRect(&r, dx, dy, &inval);
343 paint_rgn(bm, r, inval);
344 }
345}
346
347static SkBitmap::Config gConfigCycle[] = {
348 SkBitmap::kNo_Config, // none -> none
349 SkBitmap::kNo_Config, // a1 -> none
350 SkBitmap::kNo_Config, // a8 -> none
351 SkBitmap::kNo_Config, // index8 -> none
352 SkBitmap::kARGB_4444_Config, // 565 -> 4444
353 SkBitmap::kARGB_8888_Config, // 4444 -> 8888
354 SkBitmap::kRGB_565_Config // 8888 -> 565
355};
356
357static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
358 return gConfigCycle[c];
359}
360
361bool SampleWindow::nextSample() {
362 if (fCurr) {
363 fCurr = fCurr->next();
364 if (NULL == fCurr) {
365 fCurr = SkViewRegister::Head();
366 }
367 this->loadView(fCurr->factory()());
368 return true;
369 }
370 return false;
371}
372
373bool SampleWindow::onEvent(const SkEvent& evt) {
374 if (evt.isType(ANIMATING_EVENTTYPE)) {
375 if (fAnimating) {
376 this->nextSample();
377 this->postAnimatingEvent();
378 }
379 return true;
380 }
381 return this->INHERITED::onEvent(evt);
382}
383
reed@android.com0ae6b242008-12-23 16:49:54 +0000384static void cleanup_for_filename(SkString* name) {
385 char* str = name->writable_str();
386 for (int i = 0; i < name->size(); i++) {
387 switch (str[i]) {
388 case ':': str[i] = '-'; break;
389 case '/': str[i] = '-'; break;
390 case ' ': str[i] = '_'; break;
391 default: break;
392 }
393 }
394}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000395
396bool SampleWindow::onHandleChar(SkUnichar uni) {
397 int dx = 0xFF;
398 int dy = 0xFF;
399
400 switch (uni) {
401 case '5': dx = 0; dy = 0; break;
402 case '8': dx = 0; dy = -1; break;
403 case '6': dx = 1; dy = 0; break;
404 case '2': dx = 0; dy = 1; break;
405 case '4': dx = -1; dy = 0; break;
406 case '7': dx = -1; dy = -1; break;
407 case '9': dx = 1; dy = -1; break;
408 case '3': dx = 1; dy = 1; break;
409 case '1': dx = -1; dy = 1; break;
410
411 default:
412 break;
413 }
414
415 if (0xFF != dx && 0xFF != dy) {
416 if ((dx | dy) == 0) {
417 fScrollTestX = fScrollTestY = 0;
418 } else {
419 fScrollTestX += dx;
420 fScrollTestY += dy;
421 }
422 this->inval(NULL);
423 return true;
424 }
425
reed@android.com0ae6b242008-12-23 16:49:54 +0000426 switch (uni) {
427 case 'a':
428 fAnimating = !fAnimating;
429 this->postAnimatingEvent();
430 this->updateTitle();
431 return true;
432 case 'f': {
433 const char* title = this->getTitle();
434 if (title[0] == 0) {
435 title = "sampleapp";
436 }
437 SkString name(title);
438 cleanup_for_filename(&name);
439 name.append(".png");
440 if (SkImageEncoder::EncodeFile(name.c_str(), this->getBitmap(),
441 SkImageEncoder::kPNG_Type)) {
442 SkDebugf("Created %s\n", name.c_str());
443 }
444 return true;
445 }
446 default:
447 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000448 }
449
450 return this->INHERITED::onHandleChar(uni);
451}
452
453#include "SkDumpCanvas.h"
454
455bool SampleWindow::onHandleKey(SkKey key) {
456 switch (key) {
457 case kRight_SkKey:
458 if (this->nextSample()) {
459 return true;
460 }
461 break;
462 case kLeft_SkKey:
463 fCanvasType = cycle_canvastype(fCanvasType);
464 this->updateTitle();
465 this->inval(NULL);
466 return true;
467 case kUp_SkKey:
468 fUseClip = !fUseClip;
469 this->updateTitle();
470 this->inval(NULL);
471 return true;
472 case kDown_SkKey:
473 this->setConfig(cycle_configs(this->getBitmap().config()));
474 this->updateTitle();
475 return true;
476 case kOK_SkKey:
477 if (true) {
478 SkDebugfDumper dumper;
479 SkDumpCanvas dc(&dumper);
480 this->draw(&dc);
481 } else {
482 fRepeatDrawing = !fRepeatDrawing;
483 if (fRepeatDrawing) {
484 this->inval(NULL);
485 }
486 }
487 return true;
488 default:
489 break;
490 }
491 return this->INHERITED::onHandleKey(key);
492}
493
494void SampleWindow::loadView(SkView* view) {
495 SkView::F2BIter iter(this);
496 SkView* prev = iter.next();
497 if (prev) {
498 prev->detachFromParent();
499 }
500 view->setVisibleP(true);
501 this->attachChildToFront(view)->unref();
502 view->setSize(this->width(), this->height());
503
504 this->updateTitle();
505}
506
507static const char* gConfigNames[] = {
508 "unknown config",
509 "A1",
510 "A8",
511 "Index8",
512 "565",
513 "4444",
514 "8888"
515};
516
517static const char* configToString(SkBitmap::Config c) {
518 return gConfigNames[c];
519}
520
521static const char* gCanvasTypePrefix[] = {
522 "raster: ",
523 "picture: ",
524 "opengl: "
525};
526
527void SampleWindow::updateTitle() {
528 SkString title;
529
530 SkView::F2BIter iter(this);
531 SkView* view = iter.next();
532 SkEvent evt(gTitleEvtName);
533 if (view->doQuery(&evt)) {
534 title.set(evt.findString(gTitleEvtName));
535 }
536 if (title.size() == 0) {
537 title.set("<unknown>");
538 }
539
540 title.prepend(gCanvasTypePrefix[fCanvasType]);
541
542 title.prepend(" ");
543 title.prepend(configToString(this->getBitmap().config()));
544
545 if (fAnimating) {
546 title.prepend("<A> ");
547 }
548
549 this->setTitle(title.c_str());
550}
551
552void SampleWindow::onSizeChange() {
553 this->INHERITED::onSizeChange();
554
555 SkView::F2BIter iter(this);
556 SkView* view = iter.next();
557 view->setSize(this->width(), this->height());
558
559 // rebuild our clippath
560 {
561 const SkScalar W = this->width();
562 const SkScalar H = this->height();
563
564 fClipPath.reset();
565#if 0
566 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
567 SkRect r;
568 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
569 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
570 fClipPath.addRect(r);
571 }
572#else
573 SkRect r;
574 r.set(0, 0, W, H);
575 fClipPath.addRect(r, SkPath::kCCW_Direction);
576 r.set(W/4, H/4, W*3/4, H*3/4);
577 fClipPath.addRect(r, SkPath::kCW_Direction);
578#endif
579 }
580
581 this->updateTitle(); // to refresh our config
582}
583
584///////////////////////////////////////////////////////////////////////////////
585
586SkOSWindow* create_sk_window(void* hwnd) {
587 return new SampleWindow(hwnd);
588}
589
590void get_preferred_size(int* x, int* y, int* width, int* height) {
591 *x = 10;
592 *y = 50;
593 *width = 640;
594 *height = 480;
595}
596
597void application_init() {
598// setenv("ANDROID_ROOT", "../../../data", 0);
599 setenv("ANDROID_ROOT", "/android/device/data", 0);
600 SkGraphics::Init(true);
601 SkEvent::Init();
602}
603
604void application_term() {
605 SkEvent::Term();
606 SkGraphics::Term();
607}