/* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include <jni.h> #include <sys/time.h> #include <time.h> #include <android/log.h> #include <stdint.h> #include "GrContext.h" #include "SkGpuCanvas.h" #include "SkPaint.h" #include "SkString.h" #include "SkTime.h" #include "gl/GrGLConfig.h" static GrContext* make_context() { SkDebugf("---- before create\n"); GrContext* ctx = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, 0); SkDebugf("---- after create %p\n", ctx); return ctx; } /////////////////////////////////////////////////////////////////////////////// void gr_run_unittests() {} #include "FlingState.h" #include "SkTouchGesture.h" #include "SkView.h" typedef SkView* (*SkViewFactory)(); // these values must match those in Ganesh.java enum TouchState { kUnknown_TouchState, kDown_TouchState, kMoved_TouchState, kUp_TouchState }; struct State { State(); ~State(); int countSlides() const { return fFactory.count(); } const char* getSlideTitle(int index) const; void chooseSlide(int index) { SkDebugf("----- index %d\n", index); if (index < fFactory.count()) { this->setView(fFactory[index]()); } } void setViewport(int w, int h); int getWidth() const { return fViewport.fX; } int getHeight() const { return fViewport.fY; } void handleTouch(void*, TouchState, float x, float y); void applyMatrix(SkCanvas*); SkView* getView() const { return fView; } private: SkView* fView; SkIPoint fViewport; SkTouchGesture fGesture; SkTDArray<SkViewFactory> fFactory; void setView(SkView* view) { SkSafeUnref(fView); fView = view; view->setVisibleP(true); view->setClipToBounds(false); view->setSize(SkIntToScalar(fViewport.fX), SkIntToScalar(fViewport.fY)); } }; /////////////////////////////////////////////////////////////////////////////// #include "SampleCode.h" SkViewRegister* SkViewRegister::gHead; SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) { static bool gOnce; if (!gOnce) { gHead = NULL; gOnce = true; } fChain = gHead; gHead = this; } static const char gCharEvtName[] = "SampleCode_Char_Event"; static const char gKeyEvtName[] = "SampleCode_Key_Event"; static const char gTitleEvtName[] = "SampleCode_Title_Event"; static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event"; static const char gFastTextEvtName[] = "SampleCode_FastText_Event"; bool SampleCode::CharQ(const SkEvent& evt, SkUnichar* outUni) { if (evt.isType(gCharEvtName, sizeof(gCharEvtName) - 1)) { if (outUni) { *outUni = evt.getFast32(); } return true; } return false; } bool SampleCode::KeyQ(const SkEvent& evt, SkKey* outKey) { if (evt.isType(gKeyEvtName, sizeof(gKeyEvtName) - 1)) { if (outKey) { *outKey = (SkKey)evt.getFast32(); } return true; } return false; } bool SampleCode::TitleQ(const SkEvent& evt) { return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1); } void SampleCode::TitleR(SkEvent* evt, const char title[]) { GrAssert(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) { GrAssert(evt && PrefSizeQ(*evt)); SkScalar size[2]; size[0] = width; size[1] = height; evt->setScalars(gPrefSizeEvtName, 2, size); } bool SampleCode::FastTextQ(const SkEvent& evt) { return evt.isType(gFastTextEvtName, sizeof(gFastTextEvtName) - 1); } static SkMSec gAnimTime; static SkMSec gAnimTimePrev; SkMSec SampleCode::GetAnimTime() { return gAnimTime; } SkMSec SampleCode::GetAnimTimeDelta() { return gAnimTime - gAnimTimePrev; } SkScalar SampleCode::GetAnimSecondsDelta() { return SkDoubleToScalar(GetAnimTimeDelta() / 1000.0); } SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) { // since gAnimTime can be up to 32 bits, we can't convert it to a float // or we'll lose the low bits. Hence we use doubles for the intermediate // calculations double seconds = (double)gAnimTime / 1000.0; double value = SkScalarToDouble(speed) * seconds; if (period) { value = ::fmod(value, SkScalarToDouble(period)); } return SkDoubleToScalar(value); } static void drawIntoCanvas(State* state, SkCanvas* canvas) { gAnimTime = SkTime::GetMSecs(); SkView* view = state->getView(); view->draw(canvas); } /////////////////////////////////////////////////////////////////////////////// static void resetGpuState(); State::State() { fViewport.set(0, 0); const SkViewRegister* reg = SkViewRegister::Head(); while (reg) { *fFactory.append() = reg->factory(); reg = reg->next(); } SkDebugf("----- %d slides\n", fFactory.count()); fView = NULL; this->chooseSlide(0); } State::~State() { SkSafeUnref(fView); } void State::setViewport(int w, int h) { fViewport.set(w, h); if (fView) { fView->setSize(SkIntToScalar(w), SkIntToScalar(h)); } resetGpuState(); } const char* State::getSlideTitle(int index) const { SkEvent evt(gTitleEvtName); evt.setFast32(index); { SkView* view = fFactory[index](); view->doQuery(&evt); view->unref(); } return evt.findString(gTitleEvtName); } void State::handleTouch(void* owner, TouchState state, float x, float y) { switch (state) { case kDown_TouchState: fGesture.touchBegin(owner, x, y); break; case kMoved_TouchState: fGesture.touchMoved(owner, x, y); break; case kUp_TouchState: fGesture.touchEnd(owner); break; } } void State::applyMatrix(SkCanvas* canvas) { const SkMatrix& localM = fGesture.localM(); if (localM.getType() & SkMatrix::kScale_Mask) { canvas->setExternalMatrix(&localM); } canvas->concat(localM); canvas->concat(fGesture.globalM()); } static State* get_state() { static State* gState; if (NULL == gState) { gState = new State; } return gState; } /////////////////////////////////////////////////////////////////////////////// static GrContext* gContext; static int gWidth; static int gHeight; static float gX, gY; static void resetGpuState() { if (NULL == gContext) { SkDebugf("creating context for first time\n"); gContext = make_context(); } else { SkDebugf("------ gContext refcnt=%d\n", gContext->refcnt()); gContext->abandonAllTextures(); gContext->unref(); gContext = make_context(); } } static void doDraw() { if (NULL == gContext) { gContext = make_context(); } State* state = get_state(); SkBitmap viewport; viewport.setConfig(SkBitmap::kARGB_8888_Config, state->getWidth(), state->getHeight()); SkGpuCanvas canvas(gContext); canvas.setBitmapDevice(viewport); state->applyMatrix(&canvas); drawIntoCanvas(state, &canvas); GrGLCheckErr(); GrGLClearErr(); // gContext->checkError(); // gContext->clearError(); if (true) { static const int FRAME_COUNT = 32; static SkMSec gDuration; static SkMSec gNow; static int gFrameCounter; if (++gFrameCounter == FRAME_COUNT) { gFrameCounter = 0; SkMSec now = SkTime::GetMSecs(); gDuration = now - gNow; gNow = now; } int fps = (FRAME_COUNT * 1000) / gDuration; SkString str; str.printf("FPS=%3d MS=%3d", fps, gDuration / FRAME_COUNT); SkGpuCanvas c(gContext); c.setBitmapDevice(viewport); SkPaint p; p.setAntiAlias(true); SkRect r = { 0, 0, 110, 16 }; p.setColor(SK_ColorWHITE); c.drawRect(r, p); p.setColor(SK_ColorBLACK); c.drawText(str.c_str(), str.size(), 4, 12, p); } } /////////////////////////////////////////////////////////////////////////////// extern "C" { JNIEXPORT void JNICALL Java_com_tetrark_ganesh_MyRenderer_nativeSurfaceCreated( JNIEnv*, jobject); JNIEXPORT void JNICALL Java_com_tetrark_ganesh_MyRenderer_nativeViewport(JNIEnv*, jobject, jint w, jint h); JNIEXPORT void JNICALL Java_com_tetrark_ganesh_MyRenderer_nativeDrawFrame(JNIEnv*, jobject); JNIEXPORT void JNICALL Java_com_tetrark_ganesh_MyRenderer_nativeTouch(JNIEnv*, jobject, jint id, jint type, jfloat x, jfloat y); JNIEXPORT int JNICALL Java_com_tetrark_ganesh_MyRenderer_nativeCountSlides(JNIEnv*, jobject); JNIEXPORT jobject JNICALL Java_com_tetrark_ganesh_MyRenderer_nativeGetSlideTitle(JNIEnv*, jobject, jint index); JNIEXPORT void JNICALL Java_com_tetrark_ganesh_MyRenderer_nativeChooseSlide(JNIEnv*, jobject, jint index); } JNIEXPORT void JNICALL Java_com_tetrark_ganesh_MyRenderer_nativeSurfaceCreated( JNIEnv*, jobject) { SkDebugf("------ nativeSurfaceCreated\n"); resetGpuState(); SkDebugf("------ end nativeSurfaceCreated\n"); } JNIEXPORT void JNICALL Java_com_tetrark_ganesh_MyRenderer_nativeViewport(JNIEnv*, jobject, jint w, jint h) { State* state = get_state(); SkDebugf("---- state.setviewport %p %d %d\n", state, w, h); state->setViewport(w, h); SkDebugf("---- end setviewport\n"); } JNIEXPORT void JNICALL Java_com_tetrark_ganesh_MyRenderer_nativeDrawFrame(JNIEnv*, jobject) { doDraw(); } union IntPtr { jint fInt; void* fPtr; }; static void* int2ptr(jint n) { IntPtr data; data.fInt = n; return data.fPtr; } JNIEXPORT void JNICALL Java_com_tetrark_ganesh_MyRenderer_nativeTouch(JNIEnv*, jobject, jint id, jint type, jfloat x, jfloat y) { get_state()->handleTouch(int2ptr(id), (TouchState)type, x, y); } //////////// JNIEXPORT int JNICALL Java_com_tetrark_ganesh_MyRenderer_nativeCountSlides(JNIEnv*, jobject) { return get_state()->countSlides(); } JNIEXPORT jobject JNICALL Java_com_tetrark_ganesh_MyRenderer_nativeGetSlideTitle(JNIEnv* env, jobject, jint index) { return env->NewStringUTF(get_state()->getSlideTitle(index)); } JNIEXPORT void JNICALL Java_com_tetrark_ganesh_MyRenderer_nativeChooseSlide(JNIEnv*, jobject, jint index) { get_state()->chooseSlide(index); }