blob: 365f558345dc18abb8820ae0dff7a76f56e95692 [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"
5#include "SkPaint.h"
6#include "SkPicture.h"
7#include "SkStream.h"
8#include "SkWindow.h"
9
10#include "SampleCode.h"
11
reed@android.com6efdc472008-12-19 18:24:35 +000012//#define SK_SUPPORT_GL
13
14#ifdef SK_SUPPORT_GL
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include <AGL/agl.h>
16#include <OpenGL/gl.h>
reed@android.com6efdc472008-12-19 18:24:35 +000017#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000018
19#define ANIMATING_EVENTTYPE "nextSample"
20#define ANIMATING_DELAY 750
21
22#define USE_OFFSCREEN
23
24SkViewRegister* SkViewRegister::gHead;
25SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) {
26 static bool gOnce;
27 if (!gOnce) {
28 gHead = NULL;
29 gOnce = true;
30 }
31
32 fChain = gHead;
33 gHead = this;
34}
35
reed@android.com6efdc472008-12-19 18:24:35 +000036#ifdef SK_SUPPORT_GL
reed@android.com8a1c16f2008-12-17 15:59:43 +000037static AGLContext gAGLContext;
38
39static void init_gl(WindowRef wref) {
40 GLint major, minor;
41
42 aglGetVersion(&major, &minor);
43 SkDebugf("---- agl version %d %d\n", major, minor);
44
45 const GLint pixelAttrs[] = {
46 AGL_RGBA,
47 AGL_DEPTH_SIZE, 32,
48 AGL_OFFSCREEN,
49 AGL_NONE
50 };
51
52 AGLPixelFormat format = aglCreatePixelFormat(pixelAttrs);
53 SkDebugf("----- agl format %p\n", format);
54 gAGLContext = aglCreateContext(format, NULL);
55 SkDebugf("----- agl context %p\n", gAGLContext);
56 aglDestroyPixelFormat(format);
57
58 aglEnable(gAGLContext, GL_BLEND);
59 aglEnable(gAGLContext, GL_LINE_SMOOTH);
60 aglEnable(gAGLContext, GL_POINT_SMOOTH);
61 aglEnable(gAGLContext, GL_POLYGON_SMOOTH);
62
63 aglSetCurrentContext(gAGLContext);
64}
65
66static void setup_offscreen_gl(const SkBitmap& offscreen, WindowRef wref) {
67 GLboolean success = true;
68
69#ifdef USE_OFFSCREEN
70 success = aglSetOffScreen(gAGLContext,
71 offscreen.width(),
72 offscreen.height(),
73 offscreen.rowBytes(),
74 offscreen.getPixels());
75#else
76 success = aglSetWindowRef(gAGLContext, wref);
77#endif
78
79 GLenum err = aglGetError();
80 if (err) {
81 SkDebugf("---- setoffscreen %d %d %s [%d %d]\n", success, err,
82 aglErrorString(err), offscreen.width(), offscreen.height());
83 }
84
85 glEnable(GL_BLEND);
86 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
87 glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
88 glEnable(GL_TEXTURE_2D);
89
90 glClearColor(0, 0, 0, 0);
91 glClear(GL_COLOR_BUFFER_BIT);
92}
reed@android.com6efdc472008-12-19 18:24:35 +000093#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000094
95//////////////////////////////////////////////////////////////////////////////
96
97static const char gTitleEvtName[] = "SampleCode_Title_Event";
98static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event";
99
100bool SampleCode::TitleQ(const SkEvent& evt) {
101 return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1);
102}
103
104void SampleCode::TitleR(SkEvent* evt, const char title[]) {
105 SkASSERT(evt && TitleQ(*evt));
106 evt->setString(gTitleEvtName, title);
107}
108
109bool SampleCode::PrefSizeQ(const SkEvent& evt) {
110 return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1);
111}
112
113void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) {
114 SkASSERT(evt && PrefSizeQ(*evt));
115 SkScalar size[2];
116 size[0] = width;
117 size[1] = height;
118 evt->setScalars(gPrefSizeEvtName, 2, size);
119}
120
121//////////////////////////////////////////////////////////////////////////////
122
123class SampleWindow : public SkOSWindow {
124public:
125 SampleWindow(void* hwnd);
126 virtual ~SampleWindow();
127
128protected:
129 virtual void onDraw(SkCanvas* canvas);
130 virtual bool onHandleKey(SkKey key);
131 virtual bool onHandleChar(SkUnichar);
132 virtual void onSizeChange();
133
134 virtual SkCanvas* beforeChildren(SkCanvas*);
135 virtual void afterChildren(SkCanvas*);
136
137 virtual bool onEvent(const SkEvent& evt);
138
139#if 0
140 virtual bool handleChar(SkUnichar uni);
141 virtual bool handleEvent(const SkEvent& evt);
142 virtual bool handleKey(SkKey key);
143 virtual bool handleKeyUp(SkKey key);
144
145 virtual bool onClick(Click* click);
146 virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
147 virtual bool onHandleKeyUp(SkKey key);
148#endif
149private:
150 const SkViewRegister* fCurr;
151
152 SkPicture* fPicture;
153 SkGLCanvas* fGLCanvas;
154 SkPath fClipPath;
155
156 enum CanvasType {
157 kRaster_CanvasType,
158 kPicture_CanvasType,
159 kOpenGL_CanvasType
160 };
161 CanvasType fCanvasType;
162
163 bool fUseClip;
164 bool fRepeatDrawing;
165 bool fAnimating;
166
167 int fScrollTestX, fScrollTestY;
168
169 void loadView(SkView*);
170 void updateTitle();
171 bool nextSample();
172
173 void postAnimatingEvent() {
174 if (fAnimating) {
175 SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
176 evt->post(this->getSinkID(), ANIMATING_DELAY);
177 }
178 }
179
180
181 static CanvasType cycle_canvastype(CanvasType);
182
183 typedef SkOSWindow INHERITED;
184};
185
186SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
187 static const CanvasType gCT[] = {
188 kPicture_CanvasType,
189 kOpenGL_CanvasType,
190 kRaster_CanvasType
191 };
192 return gCT[ct];
193}
194
195SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
reed@android.com6efdc472008-12-19 18:24:35 +0000196#ifdef SK_SUPPORT_GL
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197 init_gl((WindowRef)hwnd);
reed@android.com6efdc472008-12-19 18:24:35 +0000198#endif
199
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 fPicture = NULL;
201 fGLCanvas = NULL;
202
203 fCanvasType = kRaster_CanvasType;
204 fUseClip = false;
205 fRepeatDrawing = false;
206 fAnimating = false;
207
208 fScrollTestX = fScrollTestY = 0;
209
210// this->setConfig(SkBitmap::kRGB_565_Config);
211 this->setConfig(SkBitmap::kARGB_8888_Config);
212 this->setVisibleP(true);
213
214 fCurr = SkViewRegister::Head();
215 this->loadView(fCurr->factory()());
216}
217
218SampleWindow::~SampleWindow() {
219 delete fPicture;
220 delete fGLCanvas;
221}
222
223void SampleWindow::onDraw(SkCanvas* canvas) {
224 if (fRepeatDrawing) {
225 this->inval(NULL);
226 }
227}
228
229#include "SkColorPriv.h"
230
231static void reverseRedAndBlue(const SkBitmap& bm) {
232 SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
233 uint8_t* p = (uint8_t*)bm.getPixels();
234 uint8_t* stop = p + bm.getSize();
235 while (p < stop) {
236 // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
237 unsigned scale = SkAlpha255To256(p[3]);
238 unsigned r = p[2];
239 unsigned b = p[0];
240 p[0] = SkAlphaMul(r, scale);
241 p[1] = SkAlphaMul(p[1], scale);
242 p[2] = SkAlphaMul(b, scale);
243 p += 4;
244 }
245}
246
247SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
reed@android.com6efdc472008-12-19 18:24:35 +0000248#ifdef SK_SUPPORT_GL
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249#ifndef USE_OFFSCREEN
250 aglSetWindowRef(gAGLContext, NULL);
251#endif
reed@android.com6efdc472008-12-19 18:24:35 +0000252#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253 switch (fCanvasType) {
254 case kRaster_CanvasType:
255 canvas = this->INHERITED::beforeChildren(canvas);
256 break;
257 case kPicture_CanvasType:
258 fPicture = new SkPicture;
259 canvas = fPicture->beginRecording(9999, 9999);
260 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000261#ifdef SK_SUPPORT_GL
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262 case kOpenGL_CanvasType: {
263 //SkGLCanvas::DeleteAllTextures(); // just for testing
264 SkDevice* device = canvas->getDevice();
265 const SkBitmap& bitmap = device->accessBitmap(true);
266 // first clear the raster bitmap, so we don't see any leftover bits
267 bitmap.eraseColor(0);
268 // now setup our glcanvas
269 setup_offscreen_gl(bitmap, (WindowRef)this->getHWND());
270 fGLCanvas = new SkGLCanvas;
271 fGLCanvas->setViewport(bitmap.width(), bitmap.height());
272 canvas = fGLCanvas;
273 break;
274 }
reed@android.com6efdc472008-12-19 18:24:35 +0000275#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 }
277
278 if (fUseClip) {
279 canvas->drawColor(0xFFFF88FF);
280 canvas->clipPath(fClipPath);
281 }
282
283 return canvas;
284}
285
286static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
287 const SkRegion& rgn) {
288 SkCanvas canvas(bm);
289 SkRegion inval(rgn);
290
291 inval.translate(r.fLeft, r.fTop);
292 canvas.clipRegion(inval);
293 canvas.drawColor(0xFFFF8080);
294}
295
296void SampleWindow::afterChildren(SkCanvas* orig) {
297 switch (fCanvasType) {
298 case kRaster_CanvasType:
299 break;
300 case kPicture_CanvasType:
301 if (false) {
302 SkPicture* pict = new SkPicture(*fPicture);
303 fPicture->unref();
304 orig->drawPicture(*pict);
305 pict->unref();
306 } if (true) {
307 SkDynamicMemoryWStream ostream;
308 fPicture->serialize(&ostream);
309 fPicture->unref();
310
311 SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
312 SkPicture pict(&istream);
313 orig->drawPicture(pict);
314 } else {
315 fPicture->draw(orig);
316 fPicture->unref();
317 }
318 fPicture = NULL;
319 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000320#ifdef SK_SUPPORT_GL
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321 case kOpenGL_CanvasType:
322 glFlush();
323 delete fGLCanvas;
324 fGLCanvas = NULL;
325#ifdef USE_OFFSCREEN
326 reverseRedAndBlue(orig->getDevice()->accessBitmap(true));
327#endif
328 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000329#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330 }
331
332// if ((fScrollTestX | fScrollTestY) != 0)
333 {
334 const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
335 int dx = fScrollTestX * 7;
336 int dy = fScrollTestY * 7;
337 SkIRect r;
338 SkRegion inval;
339
340 r.set(50, 50, 50+100, 50+100);
341 bm.scrollRect(&r, dx, dy, &inval);
342 paint_rgn(bm, r, inval);
343 }
344}
345
346static SkBitmap::Config gConfigCycle[] = {
347 SkBitmap::kNo_Config, // none -> none
348 SkBitmap::kNo_Config, // a1 -> none
349 SkBitmap::kNo_Config, // a8 -> none
350 SkBitmap::kNo_Config, // index8 -> none
351 SkBitmap::kARGB_4444_Config, // 565 -> 4444
352 SkBitmap::kARGB_8888_Config, // 4444 -> 8888
353 SkBitmap::kRGB_565_Config // 8888 -> 565
354};
355
356static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
357 return gConfigCycle[c];
358}
359
360bool SampleWindow::nextSample() {
361 if (fCurr) {
362 fCurr = fCurr->next();
363 if (NULL == fCurr) {
364 fCurr = SkViewRegister::Head();
365 }
366 this->loadView(fCurr->factory()());
367 return true;
368 }
369 return false;
370}
371
372bool SampleWindow::onEvent(const SkEvent& evt) {
373 if (evt.isType(ANIMATING_EVENTTYPE)) {
374 if (fAnimating) {
375 this->nextSample();
376 this->postAnimatingEvent();
377 }
378 return true;
379 }
380 return this->INHERITED::onEvent(evt);
381}
382
383
384bool SampleWindow::onHandleChar(SkUnichar uni) {
385 int dx = 0xFF;
386 int dy = 0xFF;
387
388 switch (uni) {
389 case '5': dx = 0; dy = 0; break;
390 case '8': dx = 0; dy = -1; break;
391 case '6': dx = 1; dy = 0; break;
392 case '2': dx = 0; dy = 1; break;
393 case '4': dx = -1; dy = 0; break;
394 case '7': dx = -1; dy = -1; break;
395 case '9': dx = 1; dy = -1; break;
396 case '3': dx = 1; dy = 1; break;
397 case '1': dx = -1; dy = 1; break;
398
399 default:
400 break;
401 }
402
403 if (0xFF != dx && 0xFF != dy) {
404 if ((dx | dy) == 0) {
405 fScrollTestX = fScrollTestY = 0;
406 } else {
407 fScrollTestX += dx;
408 fScrollTestY += dy;
409 }
410 this->inval(NULL);
411 return true;
412 }
413
414 if ('a' == uni) {
415 fAnimating = !fAnimating;
416 this->postAnimatingEvent();
417 this->updateTitle();
418 }
419
420 return this->INHERITED::onHandleChar(uni);
421}
422
423#include "SkDumpCanvas.h"
424
425bool SampleWindow::onHandleKey(SkKey key) {
426 switch (key) {
427 case kRight_SkKey:
428 if (this->nextSample()) {
429 return true;
430 }
431 break;
432 case kLeft_SkKey:
433 fCanvasType = cycle_canvastype(fCanvasType);
434 this->updateTitle();
435 this->inval(NULL);
436 return true;
437 case kUp_SkKey:
438 fUseClip = !fUseClip;
439 this->updateTitle();
440 this->inval(NULL);
441 return true;
442 case kDown_SkKey:
443 this->setConfig(cycle_configs(this->getBitmap().config()));
444 this->updateTitle();
445 return true;
446 case kOK_SkKey:
447 if (true) {
448 SkDebugfDumper dumper;
449 SkDumpCanvas dc(&dumper);
450 this->draw(&dc);
451 } else {
452 fRepeatDrawing = !fRepeatDrawing;
453 if (fRepeatDrawing) {
454 this->inval(NULL);
455 }
456 }
457 return true;
458 default:
459 break;
460 }
461 return this->INHERITED::onHandleKey(key);
462}
463
464void SampleWindow::loadView(SkView* view) {
465 SkView::F2BIter iter(this);
466 SkView* prev = iter.next();
467 if (prev) {
468 prev->detachFromParent();
469 }
470 view->setVisibleP(true);
471 this->attachChildToFront(view)->unref();
472 view->setSize(this->width(), this->height());
473
474 this->updateTitle();
475}
476
477static const char* gConfigNames[] = {
478 "unknown config",
479 "A1",
480 "A8",
481 "Index8",
482 "565",
483 "4444",
484 "8888"
485};
486
487static const char* configToString(SkBitmap::Config c) {
488 return gConfigNames[c];
489}
490
491static const char* gCanvasTypePrefix[] = {
492 "raster: ",
493 "picture: ",
494 "opengl: "
495};
496
497void SampleWindow::updateTitle() {
498 SkString title;
499
500 SkView::F2BIter iter(this);
501 SkView* view = iter.next();
502 SkEvent evt(gTitleEvtName);
503 if (view->doQuery(&evt)) {
504 title.set(evt.findString(gTitleEvtName));
505 }
506 if (title.size() == 0) {
507 title.set("<unknown>");
508 }
509
510 title.prepend(gCanvasTypePrefix[fCanvasType]);
511
512 title.prepend(" ");
513 title.prepend(configToString(this->getBitmap().config()));
514
515 if (fAnimating) {
516 title.prepend("<A> ");
517 }
518
519 this->setTitle(title.c_str());
520}
521
522void SampleWindow::onSizeChange() {
523 this->INHERITED::onSizeChange();
524
525 SkView::F2BIter iter(this);
526 SkView* view = iter.next();
527 view->setSize(this->width(), this->height());
528
529 // rebuild our clippath
530 {
531 const SkScalar W = this->width();
532 const SkScalar H = this->height();
533
534 fClipPath.reset();
535#if 0
536 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
537 SkRect r;
538 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
539 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
540 fClipPath.addRect(r);
541 }
542#else
543 SkRect r;
544 r.set(0, 0, W, H);
545 fClipPath.addRect(r, SkPath::kCCW_Direction);
546 r.set(W/4, H/4, W*3/4, H*3/4);
547 fClipPath.addRect(r, SkPath::kCW_Direction);
548#endif
549 }
550
551 this->updateTitle(); // to refresh our config
552}
553
554///////////////////////////////////////////////////////////////////////////////
555
556SkOSWindow* create_sk_window(void* hwnd) {
557 return new SampleWindow(hwnd);
558}
559
560void get_preferred_size(int* x, int* y, int* width, int* height) {
561 *x = 10;
562 *y = 50;
563 *width = 640;
564 *height = 480;
565}
566
567void application_init() {
568// setenv("ANDROID_ROOT", "../../../data", 0);
569 setenv("ANDROID_ROOT", "/android/device/data", 0);
570 SkGraphics::Init(true);
571 SkEvent::Init();
572}
573
574void application_term() {
575 SkEvent::Term();
576 SkGraphics::Term();
577}