Commit b5cf9192 authored by Gaëtan Renaudeau's avatar Gaëtan Renaudeau

continue android impl

parent 2f53b53f
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":rngl" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/../Examples/Simple/android" external.system.id="GRADLE" external.system.module.group="Simple" external.system.module.version="unspecified" type="JAVA_MODULE" version="4"> <module external.linked.project.id=":rngl" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/../Examples/AdvancedEffects/android" external.system.id="GRADLE" external.system.module.group="AdvancedEffects" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager"> <component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle"> <facet type="android-gradle" name="Android-Gradle">
<configuration> <configuration>
......
...@@ -3,10 +3,13 @@ package com.projectseptember.RNGL; ...@@ -3,10 +3,13 @@ package com.projectseptember.RNGL;
import static android.opengl.GLES20.*; import static android.opengl.GLES20.*;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.net.Uri; import android.net.Uri;
import android.opengl.GLSurfaceView; import android.opengl.GLSurfaceView;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.facebook.imagepipeline.core.ExecutorSupplier; import com.facebook.imagepipeline.core.ExecutorSupplier;
...@@ -47,7 +50,7 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E ...@@ -47,7 +50,7 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
private boolean autoRedraw; private boolean autoRedraw;
private GLData data; private GLData data;
private List<Uri> imagesToPreload; private List<Uri> imagesToPreload;
private List<Uri> preloaded = new ArrayList<>(); // FIXME double check that this works private List<Uri> preloaded = new ArrayList<>();
private Map<Uri, GLImage> images = new HashMap<>(); private Map<Uri, GLImage> images = new HashMap<>();
private List<GLTexture> contentTextures = new ArrayList<>(); private List<GLTexture> contentTextures = new ArrayList<>();
...@@ -82,7 +85,7 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E ...@@ -82,7 +85,7 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
public GLFBO getFBO (Integer id) { public GLFBO getFBO (Integer id) {
if (!fbos.containsKey(id)) { if (!fbos.containsKey(id)) {
fbos.put(id, new GLFBO()); fbos.put(id, new GLFBO(this));
} }
return fbos.get(id); return fbos.get(id);
} }
...@@ -100,7 +103,11 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E ...@@ -100,7 +103,11 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
public void onSurfaceCreated(GL10 gl, EGLConfig config) { public void onSurfaceCreated(GL10 gl, EGLConfig config) {
fbos = new HashMap<>(); fbos = new HashMap<>();
shaders = new HashMap<>(); shaders = new HashMap<>();
// TODO : need to reset GLImage and GLTexture. in a smart way (images if already loaded just need to re-set the bitmap) images = new HashMap<>();
contentTextures = new ArrayList<>();
contentBitmaps = new ArrayList<>();
renderData = null;
requestSyncData();
} }
@Override @Override
...@@ -248,6 +255,25 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E ...@@ -248,6 +255,25 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
}); });
} }
public static Bitmap captureView (View view) {
int w = view.getWidth();
int h = view.getHeight();
if (w <= 0 || h <= 0)
return Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888);
Bitmap bitmap = view.getDrawingCache();
if (bitmap == null)
view.setDrawingCacheEnabled(true);
bitmap = view.getDrawingCache();
if (bitmap == null) {
Log.e("GLCanvas", "view.getDrawingCache() is null. view="+view);
return Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888);
}
Matrix matrix = new Matrix();
matrix.postScale(1, -1);
Bitmap reversed = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
return reversed;
}
/** /**
* Snapshot the content views and save to contentBitmaps (must run in UI Thread) * Snapshot the content views and save to contentBitmaps (must run in UI Thread)
*/ */
...@@ -256,11 +282,19 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E ...@@ -256,11 +282,19 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
ViewGroup parent = (ViewGroup) this.getParent(); ViewGroup parent = (ViewGroup) this.getParent();
int count = parent == null ? 0 : parent.getChildCount() - 1; int count = parent == null ? 0 : parent.getChildCount() - 1;
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
bitmaps.add(GLTexture.captureView(parent.getChildAt(i))); View view = parent.getChildAt(i);
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
if (group.getChildCount() == 1) {
// If the content container only contain one other container,
// we will use it for rasterization. That way we screenshot without cropping.
view = group.getChildAt(0);
}
}
bitmaps.add(captureView(view));
} }
contentBitmaps = bitmaps; contentBitmaps = bitmaps;
//Log.i("GLCanvas", "syncContentBitmaps "+count+" "+parent);
return count; return count;
} }
...@@ -271,12 +305,10 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E ...@@ -271,12 +305,10 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
int size = Math.min(contentTextures.size(), contentBitmaps.size()); int size = Math.min(contentTextures.size(), contentBitmaps.size());
for (int i=0; i<size; i++) for (int i=0; i<size; i++)
contentTextures.get(i).setPixels(contentBitmaps.get(i)); contentTextures.get(i).setPixels(contentBitmaps.get(i));
//Log.i("GLCanvas", "syncContentTextures "+size);
return size; return size;
} }
public void resizeUniformContentTextures (int n) { public void resizeUniformContentTextures (int n) {
//Log.i("GLCanvas", "reiszeUniformContentTextures "+n);
int length = contentTextures.size(); int length = contentTextures.size();
if (length == n) return; if (length == n) return;
if (n < length) { if (n < length) {
...@@ -284,7 +316,7 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E ...@@ -284,7 +316,7 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
} }
else { else {
for (int i = contentTextures.size(); i < n; i++) { for (int i = contentTextures.size(); i < n; i++) {
contentTextures.add(new GLTexture()); contentTextures.add(new GLTexture(this));
} }
} }
} }
...@@ -293,6 +325,7 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E ...@@ -293,6 +325,7 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
private int countPreloaded () { private int countPreloaded () {
int nb = 0; int nb = 0;
for (Uri toload: imagesToPreload) { for (Uri toload: imagesToPreload) {
Log.i("GLCanvas", "toload: "+toload.getPath()+" = "+preloaded.contains(toload));
if (preloaded.contains(toload)) { if (preloaded.contains(toload)) {
nb++; nb++;
} }
...@@ -380,13 +413,11 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E ...@@ -380,13 +413,11 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
uniformsInteger.put(uniformName, units++); uniformsInteger.put(uniformName, units++);
if (dataUniforms.isNull(uniformName)) { if (dataUniforms.isNull(uniformName)) {
GLTexture emptyTexture = new GLTexture(); GLTexture emptyTexture = new GLTexture(this);
emptyTexture.setPixelsEmpty(); emptyTexture.setPixelsEmpty();
textures.put(uniformName, emptyTexture); textures.put(uniformName, emptyTexture);
} }
else { else {
// FIXME: in case of require() it's now a number...
// TODO: need to support this. as well as on iOS side
ReadableMap value = dataUniforms.getMap(uniformName); ReadableMap value = dataUniforms.getMap(uniformName);
String t = value.getString("type"); String t = value.getString("type");
if (t.equals("content")) { if (t.equals("content")) {
...@@ -640,10 +671,10 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E ...@@ -640,10 +671,10 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
} }
private void dispatchOnProgress (double progress, int count, int total) { private void dispatchOnProgress (double progress, int loaded, int total) {
WritableMap event = Arguments.createMap(); WritableMap event = Arguments.createMap();
event.putDouble("progress", progress); event.putDouble("progress", progress);
event.putInt("count", count); event.putInt("loaded", loaded);
event.putInt("total", total); event.putInt("total", total);
ReactContext reactContext = (ReactContext)getContext(); ReactContext reactContext = (ReactContext)getContext();
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent( reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
......
...@@ -8,10 +8,13 @@ import com.facebook.imagepipeline.memory.PoolConfig; ...@@ -8,10 +8,13 @@ import com.facebook.imagepipeline.memory.PoolConfig;
import com.facebook.imagepipeline.memory.PoolFactory; import com.facebook.imagepipeline.memory.PoolFactory;
import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.SimpleViewManager; import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ReactProp; import com.facebook.react.uimanager.ReactProp;
import java.util.Map;
public class GLCanvasManager extends SimpleViewManager<GLCanvas> { public class GLCanvasManager extends SimpleViewManager<GLCanvas> {
...@@ -77,4 +80,14 @@ public class GLCanvasManager extends SimpleViewManager<GLCanvas> { ...@@ -77,4 +80,14 @@ public class GLCanvasManager extends SimpleViewManager<GLCanvas> {
} }
return new GLCanvas(context, executorSupplier); return new GLCanvas(context, executorSupplier);
} }
@Override
public @Nullable Map getExportedCustomDirectEventTypeConstants() {
return MapBuilder.of(
"load",
MapBuilder.of("registrationName", "onLoad"),
"progress",
MapBuilder.of("registrationName", "onProgress")
);
}
} }
...@@ -2,6 +2,7 @@ package com.projectseptember.RNGL; ...@@ -2,6 +2,7 @@ package com.projectseptember.RNGL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor;
import static android.opengl.GLES20.*; import static android.opengl.GLES20.*;
...@@ -10,9 +11,32 @@ public class GLFBO { ...@@ -10,9 +11,32 @@ public class GLFBO {
private int handle; private int handle;
private int width = 0; private int width = 0;
private int height = 0; private int height = 0;
private Executor glExecutor;
/**
* GLFBO constructor as well as all methods must be called in GL Thread
* @param glExecutor is only required for finalize()
*/
public GLFBO (Executor glExecutor) {
this.glExecutor = glExecutor;
FBOState state = new FBOState();
int[] handleArr = new int[1];
glGenFramebuffers(1, handleArr, 0);
handle = handleArr[0];
int numColors = 1;
glBindFramebuffer(GL_FRAMEBUFFER, handle);
private static GLTexture initTexture (int width, int height, int attachment) { for(int i=0; i<numColors; ++i) {
GLTexture texture = new GLTexture(); color.add(initTexture(width, height, GL_COLOR_ATTACHMENT0 + i));
}
state.restore();
}
private GLTexture initTexture (int width, int height, int attachment) {
GLTexture texture = new GLTexture(glExecutor);
texture.bind(); texture.bind();
texture.setShape(width, height); texture.setShape(width, height);
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture.getHandle(), 0); glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture.getHandle(), 0);
...@@ -22,41 +46,39 @@ public class GLFBO { ...@@ -22,41 +46,39 @@ public class GLFBO {
class FBOState { class FBOState {
private int fbo; private int fbo;
private int rbo;
private int tex;
public FBOState() { public FBOState() {
int[] fbo = new int[1]; int[] fbo = new int[1];
int[] rbo = new int[1];
int[] tex = new int[1];
glGetIntegerv(GL_FRAMEBUFFER_BINDING, fbo, 0); glGetIntegerv(GL_FRAMEBUFFER_BINDING, fbo, 0);
glGetIntegerv(GL_RENDERBUFFER_BINDING, rbo, 0);
glGetIntegerv(GL_TEXTURE_BINDING_2D, tex, 0);
this.fbo = fbo[0]; this.fbo = fbo[0];
this.rbo = rbo[0];
this.tex = tex[0];
} }
private void restore() { private void restore() {
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glBindTexture(GL_TEXTURE_2D, tex);
} }
} }
public GLFBO() {
FBOState state = new FBOState();
int[] handleArr = new int[1];
glGenFramebuffers(1, handleArr, 0);
handle = handleArr[0];
int numColors = 1;
glBindFramebuffer(GL_FRAMEBUFFER, handle);
for(int i=0; i<numColors; ++i) {
color.add(initTexture(width, height, GL_COLOR_ATTACHMENT0 + i));
}
state.restore();
}
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
super.finalize(); super.finalize();
int[] handleArr = new int[] { handle }; glExecutor.execute(new Runnable() {
@Override
public void run() {
int[] handleArr = new int[]{handle};
glDeleteFramebuffers(1, handleArr, 0); glDeleteFramebuffers(1, handleArr, 0);
} }
});
}
void checkStatus () { void checkStatus () {
......
...@@ -35,7 +35,7 @@ public class GLImage { ...@@ -35,7 +35,7 @@ public class GLImage {
this.onLoad = onLoad; this.onLoad = onLoad;
this.glExecutor = glExecutor; this.glExecutor = glExecutor;
this.decodeExecutor = decodeExecutor; this.decodeExecutor = decodeExecutor;
this.texture = new GLTexture(); this.texture = new GLTexture(glExecutor);
} }
public void setSrc (Uri src) { public void setSrc (Uri src) {
...@@ -71,6 +71,7 @@ public class GLImage { ...@@ -71,6 +71,7 @@ public class GLImage {
Matrix matrix = new Matrix(); Matrix matrix = new Matrix();
matrix.postScale(1, -1); matrix.postScale(1, -1);
final Bitmap bitmap = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true); final Bitmap bitmap = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
bitmap.setHasAlpha(true);
glExecutor.execute(new Runnable() { glExecutor.execute(new Runnable() {
public void run() { public void run() {
texture.setPixels(bitmap); texture.setPixels(bitmap);
......
...@@ -37,7 +37,7 @@ public class GLShader { ...@@ -37,7 +37,7 @@ public class GLShader {
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
super.finalize(); super.finalize();
if (buffer != null) { if (buffer != null) {
glDeleteProgram(program); // FIXME: will this ever work? gl calls must be done in GL Thread... glDeleteProgram(program);
glDeleteBuffers(1, buffer, 0); glDeleteBuffers(1, buffer, 0);
} }
} }
......
...@@ -6,22 +6,35 @@ import android.graphics.Matrix; ...@@ -6,22 +6,35 @@ import android.graphics.Matrix;
import android.opengl.GLUtils; import android.opengl.GLUtils;
import android.view.View; import android.view.View;
import java.util.concurrent.Executor;
import static android.opengl.GLES20.*; import static android.opengl.GLES20.*;
public class GLTexture { public class GLTexture {
private int handle; private int handle;
private Bitmap bitmapCurrentlyUploaded = null; private Bitmap bitmapCurrentlyUploaded = null;
private Executor glExecutor;
public GLTexture () { /**
* GLTexture constructor as well as all methods must be called in GL Thread
* @param glExecutor is only required for finalize()
*/
public GLTexture (Executor glExecutor) {
this.glExecutor = glExecutor;
makeTexture(); makeTexture();
} }
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
super.finalize(); super.finalize();
bitmapCurrentlyUploaded = null;
glExecutor.execute(new Runnable() {
@Override
public void run() {
int[] handleArr = new int[] { handle }; int[] handleArr = new int[] { handle };
glDeleteTextures(1, handleArr, 0); glDeleteTextures(1, handleArr, 0);
bitmapCurrentlyUploaded = null; }
});
} }
private void makeTexture () { private void makeTexture () {
...@@ -77,20 +90,6 @@ public class GLTexture { ...@@ -77,20 +90,6 @@ public class GLTexture {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
} }
public static Bitmap captureView (View view) {
int w = view.getWidth();
int h = view.getHeight();
if (w <= 0 || h <= 0) return Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888);
Bitmap bitmap = view.getDrawingCache();
if (bitmap == null)
view.setDrawingCacheEnabled(true);
bitmap = view.getDrawingCache();
Matrix matrix = new Matrix();
matrix.postScale(1, -1);
Bitmap transformedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
return transformedBitmap;
}
public int getHandle() { public int getHandle() {
return handle; return handle;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment