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