diff options
Diffstat (limited to 'samplecode/SampleApp.cpp')
-rw-r--r-- | samplecode/SampleApp.cpp | 607 |
1 files changed, 607 insertions, 0 deletions
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp new file mode 100644 index 0000000..0d2bbbc --- /dev/null +++ b/samplecode/SampleApp.cpp @@ -0,0 +1,607 @@ +#include "SkCanvas.h" +#include "SkDevice.h" +#include "SkGLCanvas.h" +#include "SkGraphics.h" +#include "SkImageEncoder.h" +#include "SkPaint.h" +#include "SkPicture.h" +#include "SkStream.h" +#include "SkWindow.h" + +#include "SampleCode.h" + +//#define SK_SUPPORT_GL + +#ifdef SK_SUPPORT_GL +#include <AGL/agl.h> +#include <OpenGL/gl.h> +#endif + +#define ANIMATING_EVENTTYPE "nextSample" +#define ANIMATING_DELAY 750 + +#define USE_OFFSCREEN + +SkViewRegister* SkViewRegister::gHead; +SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) { + static bool gOnce; + if (!gOnce) { + gHead = NULL; + gOnce = true; + } + + fChain = gHead; + gHead = this; +} + +#ifdef SK_SUPPORT_GL +static AGLContext gAGLContext; + +static void init_gl(WindowRef wref) { + GLint major, minor; + + aglGetVersion(&major, &minor); + SkDebugf("---- agl version %d %d\n", major, minor); + + const GLint pixelAttrs[] = { + AGL_RGBA, + AGL_DEPTH_SIZE, 32, + AGL_OFFSCREEN, + AGL_NONE + }; + + AGLPixelFormat format = aglCreatePixelFormat(pixelAttrs); + SkDebugf("----- agl format %p\n", format); + gAGLContext = aglCreateContext(format, NULL); + SkDebugf("----- agl context %p\n", gAGLContext); + aglDestroyPixelFormat(format); + + aglEnable(gAGLContext, GL_BLEND); + aglEnable(gAGLContext, GL_LINE_SMOOTH); + aglEnable(gAGLContext, GL_POINT_SMOOTH); + aglEnable(gAGLContext, GL_POLYGON_SMOOTH); + + aglSetCurrentContext(gAGLContext); +} + +static void setup_offscreen_gl(const SkBitmap& offscreen, WindowRef wref) { + GLboolean success = true; + +#ifdef USE_OFFSCREEN + success = aglSetOffScreen(gAGLContext, + offscreen.width(), + offscreen.height(), + offscreen.rowBytes(), + offscreen.getPixels()); +#else + success = aglSetWindowRef(gAGLContext, wref); +#endif + + GLenum err = aglGetError(); + if (err) { + SkDebugf("---- setoffscreen %d %d %s [%d %d]\n", success, err, + aglErrorString(err), offscreen.width(), offscreen.height()); + } + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); + glEnable(GL_TEXTURE_2D); + + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); +} +#endif + +////////////////////////////////////////////////////////////////////////////// + +static const char gTitleEvtName[] = "SampleCode_Title_Event"; +static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event"; + +bool SampleCode::TitleQ(const SkEvent& evt) { + return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1); +} + +void SampleCode::TitleR(SkEvent* evt, const char title[]) { + SkASSERT(evt && TitleQ(*evt)); + evt->setString(gTitleEvtName, title); +} + +bool SampleCode::PrefSizeQ(const SkEvent& evt) { + return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1); +} + +void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) { + SkASSERT(evt && PrefSizeQ(*evt)); + SkScalar size[2]; + size[0] = width; + size[1] = height; + evt->setScalars(gPrefSizeEvtName, 2, size); +} + +////////////////////////////////////////////////////////////////////////////// + +class SampleWindow : public SkOSWindow { +public: + SampleWindow(void* hwnd); + virtual ~SampleWindow(); + +protected: + virtual void onDraw(SkCanvas* canvas); + virtual bool onHandleKey(SkKey key); + virtual bool onHandleChar(SkUnichar); + virtual void onSizeChange(); + + virtual SkCanvas* beforeChildren(SkCanvas*); + virtual void afterChildren(SkCanvas*); + + virtual bool onEvent(const SkEvent& evt); + +#if 0 + virtual bool handleChar(SkUnichar uni); + virtual bool handleEvent(const SkEvent& evt); + virtual bool handleKey(SkKey key); + virtual bool handleKeyUp(SkKey key); + + virtual bool onClick(Click* click); + virtual Click* onFindClickHandler(SkScalar x, SkScalar y); + virtual bool onHandleKeyUp(SkKey key); +#endif +private: + const SkViewRegister* fCurr; + + SkPicture* fPicture; + SkGLCanvas* fGLCanvas; + SkPath fClipPath; + + enum CanvasType { + kRaster_CanvasType, + kPicture_CanvasType, + kOpenGL_CanvasType + }; + CanvasType fCanvasType; + + bool fUseClip; + bool fRepeatDrawing; + bool fAnimating; + + int fScrollTestX, fScrollTestY; + + void loadView(SkView*); + void updateTitle(); + bool nextSample(); + + void postAnimatingEvent() { + if (fAnimating) { + SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE); + evt->post(this->getSinkID(), ANIMATING_DELAY); + } + } + + + static CanvasType cycle_canvastype(CanvasType); + + typedef SkOSWindow INHERITED; +}; + +SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) { + static const CanvasType gCT[] = { + kPicture_CanvasType, + kOpenGL_CanvasType, + kRaster_CanvasType + }; + return gCT[ct]; +} + +SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) { +#ifdef SK_SUPPORT_GL + init_gl((WindowRef)hwnd); +#endif + + fPicture = NULL; + fGLCanvas = NULL; + + fCanvasType = kRaster_CanvasType; + fUseClip = false; + fRepeatDrawing = false; + fAnimating = false; + + fScrollTestX = fScrollTestY = 0; + +// this->setConfig(SkBitmap::kRGB_565_Config); + this->setConfig(SkBitmap::kARGB_8888_Config); + this->setVisibleP(true); + + fCurr = SkViewRegister::Head(); + this->loadView(fCurr->factory()()); +} + +SampleWindow::~SampleWindow() { + delete fPicture; + delete fGLCanvas; +} + +void SampleWindow::onDraw(SkCanvas* canvas) { + if (fRepeatDrawing) { + this->inval(NULL); + } +} + +#include "SkColorPriv.h" + +static void reverseRedAndBlue(const SkBitmap& bm) { + SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config); + uint8_t* p = (uint8_t*)bm.getPixels(); + uint8_t* stop = p + bm.getSize(); + while (p < stop) { + // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply + unsigned scale = SkAlpha255To256(p[3]); + unsigned r = p[2]; + unsigned b = p[0]; + p[0] = SkAlphaMul(r, scale); + p[1] = SkAlphaMul(p[1], scale); + p[2] = SkAlphaMul(b, scale); + p += 4; + } +} + +SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) { +#ifdef SK_SUPPORT_GL +#ifndef USE_OFFSCREEN + aglSetWindowRef(gAGLContext, NULL); +#endif +#endif + switch (fCanvasType) { + case kRaster_CanvasType: + canvas = this->INHERITED::beforeChildren(canvas); + break; + case kPicture_CanvasType: + fPicture = new SkPicture; + canvas = fPicture->beginRecording(9999, 9999); + break; +#ifdef SK_SUPPORT_GL + case kOpenGL_CanvasType: { + //SkGLCanvas::DeleteAllTextures(); // just for testing + SkDevice* device = canvas->getDevice(); + const SkBitmap& bitmap = device->accessBitmap(true); + // first clear the raster bitmap, so we don't see any leftover bits + bitmap.eraseColor(0); + // now setup our glcanvas + setup_offscreen_gl(bitmap, (WindowRef)this->getHWND()); + fGLCanvas = new SkGLCanvas; + fGLCanvas->setViewport(bitmap.width(), bitmap.height()); + canvas = fGLCanvas; + break; + } +#endif + } + + if (fUseClip) { + canvas->drawColor(0xFFFF88FF); + canvas->clipPath(fClipPath); + } + + return canvas; +} + +static void paint_rgn(const SkBitmap& bm, const SkIRect& r, + const SkRegion& rgn) { + SkCanvas canvas(bm); + SkRegion inval(rgn); + + inval.translate(r.fLeft, r.fTop); + canvas.clipRegion(inval); + canvas.drawColor(0xFFFF8080); +} + +void SampleWindow::afterChildren(SkCanvas* orig) { + switch (fCanvasType) { + case kRaster_CanvasType: + break; + case kPicture_CanvasType: + if (false) { + SkPicture* pict = new SkPicture(*fPicture); + fPicture->unref(); + orig->drawPicture(*pict); + pict->unref(); + } if (true) { + SkDynamicMemoryWStream ostream; + fPicture->serialize(&ostream); + fPicture->unref(); + + SkMemoryStream istream(ostream.getStream(), ostream.getOffset()); + SkPicture pict(&istream); + orig->drawPicture(pict); + } else { + fPicture->draw(orig); + fPicture->unref(); + } + fPicture = NULL; + break; +#ifdef SK_SUPPORT_GL + case kOpenGL_CanvasType: + glFlush(); + delete fGLCanvas; + fGLCanvas = NULL; +#ifdef USE_OFFSCREEN + reverseRedAndBlue(orig->getDevice()->accessBitmap(true)); +#endif + break; +#endif + } + +// if ((fScrollTestX | fScrollTestY) != 0) + { + const SkBitmap& bm = orig->getDevice()->accessBitmap(true); + int dx = fScrollTestX * 7; + int dy = fScrollTestY * 7; + SkIRect r; + SkRegion inval; + + r.set(50, 50, 50+100, 50+100); + bm.scrollRect(&r, dx, dy, &inval); + paint_rgn(bm, r, inval); + } +} + +static SkBitmap::Config gConfigCycle[] = { + SkBitmap::kNo_Config, // none -> none + SkBitmap::kNo_Config, // a1 -> none + SkBitmap::kNo_Config, // a8 -> none + SkBitmap::kNo_Config, // index8 -> none + SkBitmap::kARGB_4444_Config, // 565 -> 4444 + SkBitmap::kARGB_8888_Config, // 4444 -> 8888 + SkBitmap::kRGB_565_Config // 8888 -> 565 +}; + +static SkBitmap::Config cycle_configs(SkBitmap::Config c) { + return gConfigCycle[c]; +} + +bool SampleWindow::nextSample() { + if (fCurr) { + fCurr = fCurr->next(); + if (NULL == fCurr) { + fCurr = SkViewRegister::Head(); + } + this->loadView(fCurr->factory()()); + return true; + } + return false; +} + +bool SampleWindow::onEvent(const SkEvent& evt) { + if (evt.isType(ANIMATING_EVENTTYPE)) { + if (fAnimating) { + this->nextSample(); + this->postAnimatingEvent(); + } + return true; + } + return this->INHERITED::onEvent(evt); +} + +static void cleanup_for_filename(SkString* name) { + char* str = name->writable_str(); + for (int i = 0; i < name->size(); i++) { + switch (str[i]) { + case ':': str[i] = '-'; break; + case '/': str[i] = '-'; break; + case ' ': str[i] = '_'; break; + default: break; + } + } +} + +bool SampleWindow::onHandleChar(SkUnichar uni) { + int dx = 0xFF; + int dy = 0xFF; + + switch (uni) { + case '5': dx = 0; dy = 0; break; + case '8': dx = 0; dy = -1; break; + case '6': dx = 1; dy = 0; break; + case '2': dx = 0; dy = 1; break; + case '4': dx = -1; dy = 0; break; + case '7': dx = -1; dy = -1; break; + case '9': dx = 1; dy = -1; break; + case '3': dx = 1; dy = 1; break; + case '1': dx = -1; dy = 1; break; + + default: + break; + } + + if (0xFF != dx && 0xFF != dy) { + if ((dx | dy) == 0) { + fScrollTestX = fScrollTestY = 0; + } else { + fScrollTestX += dx; + fScrollTestY += dy; + } + this->inval(NULL); + return true; + } + + switch (uni) { + case 'a': + fAnimating = !fAnimating; + this->postAnimatingEvent(); + this->updateTitle(); + return true; + case 'f': { + const char* title = this->getTitle(); + if (title[0] == 0) { + title = "sampleapp"; + } + SkString name(title); + cleanup_for_filename(&name); + name.append(".png"); + if (SkImageEncoder::EncodeFile(name.c_str(), this->getBitmap(), + SkImageEncoder::kPNG_Type, 100)) { + SkDebugf("Created %s\n", name.c_str()); + } + return true; + } + default: + break; + } + + return this->INHERITED::onHandleChar(uni); +} + +#include "SkDumpCanvas.h" + +bool SampleWindow::onHandleKey(SkKey key) { + switch (key) { + case kRight_SkKey: + if (this->nextSample()) { + return true; + } + break; + case kLeft_SkKey: + fCanvasType = cycle_canvastype(fCanvasType); + this->updateTitle(); + this->inval(NULL); + return true; + case kUp_SkKey: + fUseClip = !fUseClip; + this->updateTitle(); + this->inval(NULL); + return true; + case kDown_SkKey: + this->setConfig(cycle_configs(this->getBitmap().config())); + this->updateTitle(); + return true; + case kOK_SkKey: + if (true) { + SkDebugfDumper dumper; + SkDumpCanvas dc(&dumper); + this->draw(&dc); + } else { + fRepeatDrawing = !fRepeatDrawing; + if (fRepeatDrawing) { + this->inval(NULL); + } + } + return true; + default: + break; + } + return this->INHERITED::onHandleKey(key); +} + +void SampleWindow::loadView(SkView* view) { + SkView::F2BIter iter(this); + SkView* prev = iter.next(); + if (prev) { + prev->detachFromParent(); + } + view->setVisibleP(true); + this->attachChildToFront(view)->unref(); + view->setSize(this->width(), this->height()); + + this->updateTitle(); +} + +static const char* gConfigNames[] = { + "unknown config", + "A1", + "A8", + "Index8", + "565", + "4444", + "8888" +}; + +static const char* configToString(SkBitmap::Config c) { + return gConfigNames[c]; +} + +static const char* gCanvasTypePrefix[] = { + "raster: ", + "picture: ", + "opengl: " +}; + +void SampleWindow::updateTitle() { + SkString title; + + SkView::F2BIter iter(this); + SkView* view = iter.next(); + SkEvent evt(gTitleEvtName); + if (view->doQuery(&evt)) { + title.set(evt.findString(gTitleEvtName)); + } + if (title.size() == 0) { + title.set("<unknown>"); + } + + title.prepend(gCanvasTypePrefix[fCanvasType]); + + title.prepend(" "); + title.prepend(configToString(this->getBitmap().config())); + + if (fAnimating) { + title.prepend("<A> "); + } + + this->setTitle(title.c_str()); +} + +void SampleWindow::onSizeChange() { + this->INHERITED::onSizeChange(); + + SkView::F2BIter iter(this); + SkView* view = iter.next(); + view->setSize(this->width(), this->height()); + + // rebuild our clippath + { + const SkScalar W = this->width(); + const SkScalar H = this->height(); + + fClipPath.reset(); +#if 0 + for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) { + SkRect r; + r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30)); + for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0)) + fClipPath.addRect(r); + } +#else + SkRect r; + r.set(0, 0, W, H); + fClipPath.addRect(r, SkPath::kCCW_Direction); + r.set(W/4, H/4, W*3/4, H*3/4); + fClipPath.addRect(r, SkPath::kCW_Direction); +#endif + } + + this->updateTitle(); // to refresh our config +} + +/////////////////////////////////////////////////////////////////////////////// + +SkOSWindow* create_sk_window(void* hwnd) { + return new SampleWindow(hwnd); +} + +void get_preferred_size(int* x, int* y, int* width, int* height) { + *x = 10; + *y = 50; + *width = 640; + *height = 480; +} + +void application_init() { +// setenv("ANDROID_ROOT", "../../../data", 0); + setenv("ANDROID_ROOT", "/android/device/data", 0); + SkGraphics::Init(true); + SkEvent::Init(); +} + +void application_term() { + SkEvent::Term(); + SkGraphics::Term(); +} |