diff --git a/android/rngl.iml b/android/rngl.iml
new file mode 100644
index 0000000000000000000000000000000000000000..686ef627749ca7cfc9b593d3a04d650c0440292d
--- /dev/null
+++ b/android/rngl.iml
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ generateDebugAndroidTestSources
+ generateDebugSources
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/src/main/java/com/projectseptember/RNGL/GLCanvas.java b/android/src/main/java/com/projectseptember/RNGL/GLCanvas.java
index 54fd4a930c37e4df1773645cc010e2a1756d4de1..d39b9d430dfa0ccb22181dda35f30579051a2633 100644
--- a/android/src/main/java/com/projectseptember/RNGL/GLCanvas.java
+++ b/android/src/main/java/com/projectseptember/RNGL/GLCanvas.java
@@ -9,6 +9,7 @@ import android.opengl.GLSurfaceView;
import android.util.DisplayMetrics;
import android.view.ViewGroup;
+import com.facebook.imagepipeline.core.ExecutorSupplier;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
@@ -28,13 +29,12 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
+import java.util.concurrent.Executor;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
-public class GLCanvas
- extends GLSurfaceView
- implements GLSurfaceView.Renderer, RunInGLThread {
+public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, Executor {
private ReactContext reactContext;
private RNGLContext rnglContext;
@@ -55,10 +55,13 @@ public class GLCanvas
private Map shaders;
private Map fbos;
+ private ExecutorSupplier executorSupplier;
+ private final Queue mRunOnDraw = new LinkedList<>();
- public GLCanvas(ThemedReactContext context) {
+ public GLCanvas(ThemedReactContext context, ExecutorSupplier executorSupplier) {
super(context);
reactContext = context;
+ this.executorSupplier = executorSupplier;
rnglContext = context.getNativeModule(RNGLContext.class);
setEGLContextClientVersion(2);
@@ -110,7 +113,7 @@ public class GLCanvas
if (contentTextures.size() != this.nbContentTextures)
resizeUniformContentTextures(nbContentTextures);
- syncEventsThrough(); // FIXME, really need to do this ?
+ syncEventsThrough(); // FIXME: need to do this here?
if (!preloadingDone) {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -219,8 +222,8 @@ public class GLCanvas
// Sync methods
- private final Queue mRunOnDraw = new LinkedList<>();
- public void runInGLThread (final Runnable runnable) {
+ @Override
+ public void execute (final Runnable runnable) {
synchronized (mRunOnDraw) {
mRunOnDraw.add(runnable);
requestRender();
@@ -235,7 +238,7 @@ public class GLCanvas
}
public void requestSyncData () {
- runInGLThread(new Runnable() {
+ execute(new Runnable() {
public void run() {
if (ensureCompiledShader(data))
syncData();
@@ -343,7 +346,7 @@ public class GLCanvas
return resolveSrc(src);
}
- public GLRenderData recSyncData (GLData data, HashMap images) {
+ private GLRenderData recSyncData (GLData data, HashMap images) {
Map prevImages = this.images;
GLShader shader = getShader(data.shader);
@@ -411,7 +414,7 @@ public class GLCanvas
images.put(src, image);
}
if (image == null) {
- image = new GLImage(reactContext.getApplicationContext(), this, new Runnable() {
+ image = new GLImage(this, executorSupplier.forDecode(), new Runnable() {
public void run() {
onImageLoad(src);
}
@@ -561,14 +564,14 @@ public class GLCanvas
}
}
- public void syncData () {
+ private void syncData () {
if (data == null) return;
HashMap images = new HashMap<>();
renderData = recSyncData(data, images);
this.images = images;
}
- public void recRender (GLRenderData renderData) {
+ private void recRender (GLRenderData renderData) {
DisplayMetrics dm = reactContext.getResources().getDisplayMetrics();
int w = Float.valueOf(renderData.width.floatValue() * dm.density).intValue();
@@ -618,7 +621,7 @@ public class GLCanvas
glDrawArrays(GL_TRIANGLES, 0, 6);
}
- public void render () {
+ private void render () {
if (renderData == null) return;
syncContentTextures();
@@ -631,13 +634,13 @@ public class GLCanvas
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
}
- public void syncEventsThrough () {
+ private void syncEventsThrough () {
// TODO: figure out how to do this...
// For some reason, the click through is half working
}
- private void dispatchOnProgress(double progress, int count, int total) {
+ private void dispatchOnProgress (double progress, int count, int total) {
WritableMap event = Arguments.createMap();
event.putDouble("progress", progress);
event.putInt("count", count);
@@ -649,7 +652,7 @@ public class GLCanvas
event);
}
- public void dispatchOnLoad () {
+ private void dispatchOnLoad () {
WritableMap event = Arguments.createMap();
ReactContext reactContext = (ReactContext)getContext();
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
diff --git a/android/src/main/java/com/projectseptember/RNGL/GLCanvasManager.java b/android/src/main/java/com/projectseptember/RNGL/GLCanvasManager.java
index 341a9d7e9597c4d77dfc6c68efbe423aa32d4fb7..8a2cc48e2c74000b0784931ff683510d01fa5959 100644
--- a/android/src/main/java/com/projectseptember/RNGL/GLCanvasManager.java
+++ b/android/src/main/java/com/projectseptember/RNGL/GLCanvasManager.java
@@ -2,19 +2,23 @@ package com.projectseptember.RNGL;
import android.support.annotation.Nullable;
+import com.facebook.imagepipeline.core.DefaultExecutorSupplier;
+import com.facebook.imagepipeline.core.ExecutorSupplier;
+import com.facebook.imagepipeline.memory.PoolConfig;
+import com.facebook.imagepipeline.memory.PoolFactory;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ReactProp;
-import java.util.Locale;
-
public class GLCanvasManager extends SimpleViewManager {
public static final String REACT_CLASS = "GLCanvas";
+ private ExecutorSupplier executorSupplier;
+
@ReactProp(name="nbContentTextures")
public void setNbContentTextures (GLCanvas view, int nbContentTextures) {
view.setNbContentTextures(nbContentTextures);
@@ -66,6 +70,11 @@ public class GLCanvasManager extends SimpleViewManager {
@Override
public GLCanvas createViewInstance (ThemedReactContext context) {
- return new GLCanvas(context);
+ if (executorSupplier == null) {
+ PoolFactory poolFactory = new PoolFactory(PoolConfig.newBuilder().build());
+ int numCpuBoundThreads = poolFactory.getFlexByteArrayPoolMaxNumThreads();
+ executorSupplier = new DefaultExecutorSupplier(numCpuBoundThreads);
+ }
+ return new GLCanvas(context, executorSupplier);
}
}
diff --git a/android/src/main/java/com/projectseptember/RNGL/GLImage.java b/android/src/main/java/com/projectseptember/RNGL/GLImage.java
index 39e641c9f7867667726c52a67aaee5d6f387e98d..2aa8f652959de675931df7730d5a2966c99a3ef6 100644
--- a/android/src/main/java/com/projectseptember/RNGL/GLImage.java
+++ b/android/src/main/java/com/projectseptember/RNGL/GLImage.java
@@ -1,75 +1,90 @@
package com.projectseptember.RNGL;
import android.content.Context;
-import android.database.Cursor;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.net.Uri;
-import android.os.AsyncTask;
-import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.util.Log;
+import com.facebook.common.references.CloseableReference;
import com.facebook.common.util.UriUtil;
+import com.facebook.datasource.DataSource;
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
+import com.facebook.imagepipeline.image.CloseableImage;
+import com.facebook.imagepipeline.request.ImageRequest;
+import com.facebook.imagepipeline.request.ImageRequestBuilder;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
+import java.util.concurrent.Executor;
/*
This class is maintained and inspired from
https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
-also inspired from
-https://github.com/CyberAgent/android-gpuimage/blob/master/library/src/jp/co/cyberagent/android/gpuimage/GPUImage.java
*/
-public class GLImage { // TODO : we need to check support for local images
- private final Context context;
+public class GLImage {
+
private Uri src;
private GLTexture texture;
-
- private boolean isDirty;
- private AsyncTask task;
- private Runnable onload;
- private RunInGLThread glScheduler;
-
- public GLImage (Context context, RunInGLThread glScheduler, Runnable onload) {
- this.context = context;
- this.onload = onload;
- this.glScheduler = glScheduler;
+ private Runnable onLoad;
+ private Executor glExecutor;
+ private Executor decodeExecutor;
+ private DataSource> pending;
+
+ public GLImage (Executor glExecutor, Executor decodeExecutor, Runnable onLoad) {
+ this.onLoad = onLoad;
+ this.glExecutor = glExecutor;
+ this.decodeExecutor = decodeExecutor;
this.texture = new GLTexture();
}
- public void setSrc(Uri src) {
- if (this.src == src) return;
+ public void setSrc (Uri src) {
+ if (this.src == src || this.src!=null && this.src.equals(src)) return;
this.src = src;
reloadImage();
}
private void reloadImage () {
- isDirty = true;
+ if (pending != null && !pending.isFinished())
+ pending.close();
+
+ final Uri uri = src;
+ ImageRequest imageRequest = ImageRequestBuilder
+ .newBuilderWithSource(uri)
+ .build();
+
+ pending = Fresco.getImagePipeline().fetchDecodedImage(imageRequest, null);
+
+ pending.subscribe(new BaseBitmapDataSubscriber() {
+ @Override
+ protected void onNewResultImpl(@Nullable Bitmap bitmap) {
+ onLoad(bitmap);
+ }
+ @Override
+ protected void onFailureImpl(DataSource> dataSource) {
+ Log.e("GLImage", "Failed to load '" + uri.getPath() + "'", dataSource.getFailureCause());
+ }
+ }, decodeExecutor);
}
- public void onLoad (final Bitmap bitmap) {
- glScheduler.runInGLThread(new Runnable() {
+ public void onLoad (final Bitmap source) {
+ Matrix matrix = new Matrix();
+ matrix.postScale(1, -1);
+ final Bitmap bitmap = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
+ glExecutor.execute(new Runnable() {
public void run() {
- Log.i("GLImage", "loaded="+src.getPath());
texture.setPixels(bitmap);
- onload.run();
+ bitmap.recycle();
+ onLoad.run();
}
});
}
public GLTexture getTexture() {
- if (isDirty) {
- if (task != null) task.cancel(true);
- task = new LoadImageUriTask(this, src).execute();
- isDirty = false;
- }
return texture;
}
- public static @Nullable Uri getResourceDrawableUri(Context context, @Nullable String name) {
+ public static @Nullable Uri getResourceDrawableUri (Context context, @Nullable String name) {
if (name == null || name.isEmpty()) {
return null;
}
@@ -83,104 +98,4 @@ public class GLImage { // TODO : we need to check support for local images
.path(String.valueOf(resId))
.build();
}
-
-
- private static class LoadImageUriTask extends LoadImageTask {
-
- private final Uri mUri;
-
- public LoadImageUriTask(GLImage gpuImage, Uri uri) {
- super(gpuImage);
- mUri = uri;
- }
-
- @Override
- protected Bitmap decode(BitmapFactory.Options options) {
- Log.i("GLImage", "loading...="+mUri.getPath());
- // FIXME: image loading is very long (probably decoding)... possible to re-use some React Native work ?
- try {
- InputStream inputStream;
- if (mUri.getScheme().startsWith("http") || mUri.getScheme().startsWith("https")) {
- inputStream = new URL(mUri.toString()).openStream();
- } else {
- inputStream = glImage.context.getContentResolver().openInputStream(mUri);
- }
- return BitmapFactory.decodeStream(inputStream, null, options);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
-
- @Override
- protected int getImageOrientation() throws IOException {
- Cursor cursor = glImage.context.getContentResolver().query(mUri,
- new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
-
- if (cursor == null || cursor.getCount() != 1) {
- return 0;
- }
-
- cursor.moveToFirst();
- int orientation = cursor.getInt(0);
- cursor.close();
- return orientation;
- }
- }
-
- private static abstract class LoadImageTask extends AsyncTask {
-
- protected GLImage glImage;
-
- public LoadImageTask (GLImage glImage) {
- this.glImage = glImage;
- }
-
- @Override
- protected Bitmap doInBackground(Void... params) {
- return loadResizedImage();
- }
-
- @Override
- protected void onPostExecute(Bitmap bitmap) {
- super.onPostExecute(bitmap);
- glImage.onLoad(bitmap);
- }
-
- protected abstract Bitmap decode(BitmapFactory.Options options);
-
- private Bitmap loadResizedImage() {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- decode(options);
- options = new BitmapFactory.Options();
- options.inPreferredConfig = Bitmap.Config.RGB_565;
- options.inTempStorage = new byte[32 * 1024];
- Bitmap bitmap = decode(options);
- if (bitmap == null) {
- return null;
- }
-
- Bitmap transformedBitmap;
- Matrix matrix = new Matrix();
-
- try {
- int orientation = getImageOrientation();
- if (orientation != 0) {
- matrix.postRotate(orientation);
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- matrix.postScale(1, -1);
-
- transformedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
- bitmap.recycle();
-
- return transformedBitmap;
- }
-
- protected abstract int getImageOrientation() throws IOException;
- }
}
diff --git a/android/src/main/java/com/projectseptember/RNGL/RunInGLThread.java b/android/src/main/java/com/projectseptember/RNGL/RunInGLThread.java
deleted file mode 100644
index 7cadfa8de65f7c35fe22349f955707959ee53f41..0000000000000000000000000000000000000000
--- a/android/src/main/java/com/projectseptember/RNGL/RunInGLThread.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.projectseptember.RNGL;
-
-public interface RunInGLThread {
- void runInGLThread(final Runnable runnable);
-}