1 2 /* 3 * Copyright 2018 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 #include <jni.h> 10 #include <math.h> 11 #include <string> 12 #include <utility> 13 #include <SkColor.h> 14 #include <SkCanvas.h> 15 #include <SkBitmap.h> 16 #include <SkSurface.h> 17 #include <SkTime.h> 18 19 #include <GrContextOptions.h> 20 #include <GrContext.h> 21 #include <gl/GrGLInterface.h> 22 #include <GrBackendSurface.h> 23 #include <gl/GrGLTypes.h> 24 25 #include <Skottie.h> 26 27 #include <GLES2/gl2.h> 28 #include <GLES2/gl2ext.h> 29 30 #include <GLES3/gl3.h> 31 #include <android/trace.h> 32 #include "JavaInputStreamAdaptor.h" 33 34 #define STENCIL_BUFFER_SIZE 8 35 36 /*#define ATRACE_NAME(name) ScopedTrace ___tracer(name) 37 38 // ATRACE_CALL is an ATRACE_NAME that uses the current function name. 39 #define ATRACE_CALL() ATRACE_NAME(__FUNCTION__) 40 namespace { 41 class ScopedTrace { 42 public: 43 inline ScopedTrace(const char *name) { 44 ATrace_beginSection(name); 45 } 46 47 inline ~ScopedTrace() { 48 ATrace_endSection(); 49 } 50 }; 51 52 }*/ 53 54 //disable atrace 55 #define ATRACE_NAME(name) 56 #define ATRACE_CALL() 57 58 struct SkottieRunner { 59 sk_sp<GrContext> mGrContext; 60 }; 61 62 extern "C" JNIEXPORT jlong 63 JNICALL 64 Java_org_skia_skottie_SkottieRunner_nCreateProxy(JNIEnv *env, jclass clazz) { 65 sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface()); 66 if (!glInterface.get()) { 67 return 0; 68 } 69 70 GrContextOptions options; 71 options.fDisableDistanceFieldPaths = true; 72 options.fDisableCoverageCountingPaths = true; 73 sk_sp<GrContext> grContext = GrContext::MakeGL(std::move(glInterface), options); 74 if (!grContext.get()) { 75 return 0; 76 } 77 78 SkottieRunner* skottie = new SkottieRunner(); 79 skottie->mGrContext = grContext; 80 81 return (jlong) skottie; 82 } 83 84 extern "C" JNIEXPORT void 85 JNICALL 86 Java_org_skia_skottie_SkottieRunner_nDeleteProxy(JNIEnv *env, jclass clazz, jlong nativeProxy) { 87 if (!nativeProxy) { 88 return; 89 } 90 SkottieRunner* skottie = reinterpret_cast<SkottieRunner*>(nativeProxy); 91 if (skottie->mGrContext) { 92 skottie->mGrContext->releaseResourcesAndAbandonContext(); 93 skottie->mGrContext.reset(); 94 } 95 delete skottie; 96 } 97 98 struct SkottieAnimation { 99 SkottieRunner *mRunner; 100 std::unique_ptr<SkStream> mStream; 101 sk_sp<skottie::Animation> mAnimation; 102 long mTimeBase; 103 float mDuration; //in milliseconds 104 }; 105 106 extern "C" JNIEXPORT jlong 107 JNICALL 108 Java_org_skia_skottie_SkottieRunner_00024SkottieAnimationImpl_nCreateProxy(JNIEnv *env, jobject clazz, 109 jlong runner, jobject is, 110 jbyteArray storage) { 111 112 if (!runner) { 113 return 0; 114 } 115 SkottieRunner *skottieRunner = reinterpret_cast<SkottieRunner*>(runner); 116 std::unique_ptr<SkStream> stream(CopyJavaInputStream(env, is, storage)); 117 if (!stream.get()) { 118 // Cannot create a stream 119 return 0; 120 } 121 122 SkottieAnimation* skottieAnimation = new SkottieAnimation(); 123 skottieAnimation->mRunner = skottieRunner; 124 skottieAnimation->mStream = std::move(stream); 125 126 skottieAnimation->mAnimation = skottie::Animation::Make(skottieAnimation->mStream.get()); 127 skottieAnimation->mTimeBase = 0.0f; // force a time reset 128 skottieAnimation->mDuration = 1000 * skottieAnimation->mAnimation->duration(); 129 130 if (!skottieAnimation->mAnimation) { 131 //failed to load Bodymovin animation 132 delete skottieAnimation; 133 return 0; 134 } 135 136 return (jlong) skottieAnimation; 137 } 138 139 extern "C" JNIEXPORT void 140 JNICALL 141 Java_org_skia_skottie_SkottieRunner_00024SkottieAnimationImpl_nDeleteProxy(JNIEnv *env, jclass clazz, 142 jlong nativeProxy) { 143 if (!nativeProxy) { 144 return; 145 } 146 SkottieAnimation* skottieAnimation = reinterpret_cast<SkottieAnimation*>(nativeProxy); 147 delete skottieAnimation; 148 } 149 150 extern "C" JNIEXPORT void 151 JNICALL 152 Java_org_skia_skottie_SkottieRunner_00024SkottieAnimationImpl_nDrawFrame(JNIEnv *env, jclass clazz, 153 jlong nativeProxy, jint width, 154 jint height, 155 jboolean wideColorGamut, 156 jfloat progress) { 157 ATRACE_NAME("SkottieDrawFrame"); 158 if (!nativeProxy) { 159 return; 160 } 161 SkottieAnimation* skottieAnimation = reinterpret_cast<SkottieAnimation*>(nativeProxy); 162 163 auto grContext = skottieAnimation->mRunner->mGrContext; 164 165 if (!grContext) { 166 return; 167 } 168 169 SkColorType colorType; 170 // setup surface for fbo0 171 GrGLFramebufferInfo fboInfo; 172 fboInfo.fFBOID = 0; 173 if (wideColorGamut) { 174 fboInfo.fFormat = GL_RGBA16F; 175 colorType = kRGBA_F16_SkColorType; 176 } else { 177 fboInfo.fFormat = GL_RGBA8; 178 colorType = kN32_SkColorType; 179 } 180 GrBackendRenderTarget backendRT(width, height, 0, STENCIL_BUFFER_SIZE, fboInfo); 181 182 SkSurfaceProps props(0, kUnknown_SkPixelGeometry); 183 184 sk_sp<SkSurface> renderTarget(SkSurface::MakeFromBackendRenderTarget( 185 grContext.get(), backendRT, kBottomLeft_GrSurfaceOrigin, colorType, 186 nullptr, &props)); 187 188 auto canvas = renderTarget->getCanvas(); 189 canvas->clear(SK_ColorTRANSPARENT); 190 if (skottieAnimation->mAnimation) { 191 skottieAnimation->mAnimation->seek(progress); 192 193 SkAutoCanvasRestore acr(canvas, true); 194 SkRect bounds = SkRect::MakeWH(width, height); 195 skottieAnimation->mAnimation->render(canvas, &bounds); 196 } 197 198 canvas->flush(); 199 } 200 201 extern "C" JNIEXPORT jlong 202 JNICALL 203 Java_org_skia_skottie_SkottieRunner_00024SkottieAnimationImpl_nGetDuration(JNIEnv *env, 204 jclass clazz, 205 jlong nativeProxy) { 206 if (!nativeProxy) { 207 return 0; 208 } 209 SkottieAnimation* skottieAnimation = reinterpret_cast<SkottieAnimation*>(nativeProxy); 210 return (jlong) skottieAnimation->mDuration; 211 } 212