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

continue android impl

parent 2f53b53f
<?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">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
......
......@@ -3,10 +3,13 @@ package com.projectseptember.RNGL;
import static android.opengl.GLES20.*;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.net.Uri;
import android.opengl.GLSurfaceView;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.facebook.imagepipeline.core.ExecutorSupplier;
......@@ -47,7 +50,7 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
private boolean autoRedraw;
private GLData data;
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 List<GLTexture> contentTextures = new ArrayList<>();
......@@ -82,7 +85,7 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
public GLFBO getFBO (Integer id) {
if (!fbos.containsKey(id)) {
fbos.put(id, new GLFBO());
fbos.put(id, new GLFBO(this));
}
return fbos.get(id);
}
......@@ -100,7 +103,11 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
fbos = 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
......@@ -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)
*/
......@@ -256,11 +282,19 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
ViewGroup parent = (ViewGroup) this.getParent();
int count = parent == null ? 0 : parent.getChildCount() - 1;
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;
//Log.i("GLCanvas", "syncContentBitmaps "+count+" "+parent);
return count;
}
......@@ -271,12 +305,10 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
int size = Math.min(contentTextures.size(), contentBitmaps.size());
for (int i=0; i<size; i++)
contentTextures.get(i).setPixels(contentBitmaps.get(i));
//Log.i("GLCanvas", "syncContentTextures "+size);
return size;
}
public void resizeUniformContentTextures (int n) {
//Log.i("GLCanvas", "reiszeUniformContentTextures "+n);
int length = contentTextures.size();
if (length == n) return;
if (n < length) {
......@@ -284,7 +316,7 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
}
else {
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
private int countPreloaded () {
int nb = 0;
for (Uri toload: imagesToPreload) {
Log.i("GLCanvas", "toload: "+toload.getPath()+" = "+preloaded.contains(toload));
if (preloaded.contains(toload)) {
nb++;
}
......@@ -380,13 +413,11 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
uniformsInteger.put(uniformName, units++);
if (dataUniforms.isNull(uniformName)) {
GLTexture emptyTexture = new GLTexture();
GLTexture emptyTexture = new GLTexture(this);
emptyTexture.setPixelsEmpty();
textures.put(uniformName, emptyTexture);
}
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);
String t = value.getString("type");
if (t.equals("content")) {
......@@ -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();
event.putDouble("progress", progress);
event.putInt("count", count);
event.putInt("loaded", loaded);
event.putInt("total", total);
ReactContext reactContext = (ReactContext)getContext();
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
......
......@@ -8,10 +8,13 @@ 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.common.MapBuilder;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ReactProp;
import java.util.Map;
public class GLCanvasManager extends SimpleViewManager<GLCanvas> {
......@@ -77,4 +80,14 @@ public class GLCanvasManager extends SimpleViewManager<GLCanvas> {
}
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;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import static android.opengl.GLES20.*;
......@@ -10,9 +11,32 @@ public class GLFBO {
private int handle;
private int width = 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);
for(int i=0; i<numColors; ++i) {
color.add(initTexture(width, height, GL_COLOR_ATTACHMENT0 + i));
}
state.restore();
}
private static GLTexture initTexture (int width, int height, int attachment) {
GLTexture texture = new GLTexture();
private GLTexture initTexture (int width, int height, int attachment) {
GLTexture texture = new GLTexture(glExecutor);
texture.bind();
texture.setShape(width, height);
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture.getHandle(), 0);
......@@ -22,40 +46,38 @@ public class GLFBO {
class FBOState {
private int fbo;
private int rbo;
private int tex;
public FBOState() {
int[] fbo = new int[1];
int[] rbo = new int[1];
int[] tex = new int[1];
glGetIntegerv(GL_FRAMEBUFFER_BINDING, fbo, 0);
glGetIntegerv(GL_RENDERBUFFER_BINDING, rbo, 0);
glGetIntegerv(GL_TEXTURE_BINDING_2D, tex, 0);
this.fbo = fbo[0];
this.rbo = rbo[0];
this.tex = tex[0];
}
private void restore() {
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
protected void finalize() throws Throwable {
super.finalize();
int[] handleArr = new int[] { handle };
glDeleteFramebuffers(1, handleArr, 0);
glExecutor.execute(new Runnable() {
@Override
public void run() {
int[] handleArr = new int[]{handle};
glDeleteFramebuffers(1, handleArr, 0);
}
});
}
......
......@@ -35,7 +35,7 @@ public class GLImage {
this.onLoad = onLoad;
this.glExecutor = glExecutor;
this.decodeExecutor = decodeExecutor;
this.texture = new GLTexture();
this.texture = new GLTexture(glExecutor);
}
public void setSrc (Uri src) {
......@@ -71,6 +71,7 @@ public class GLImage {
Matrix matrix = new Matrix();
matrix.postScale(1, -1);
final Bitmap bitmap = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
bitmap.setHasAlpha(true);
glExecutor.execute(new Runnable() {
public void run() {
texture.setPixels(bitmap);
......
......@@ -37,7 +37,7 @@ public class GLShader {
protected void finalize() throws Throwable {
super.finalize();
if (buffer != null) {
glDeleteProgram(program); // FIXME: will this ever work? gl calls must be done in GL Thread...
glDeleteProgram(program);
glDeleteBuffers(1, buffer, 0);
}
}
......
......@@ -6,22 +6,35 @@ import android.graphics.Matrix;
import android.opengl.GLUtils;
import android.view.View;
import java.util.concurrent.Executor;
import static android.opengl.GLES20.*;
public class GLTexture {
private int handle;
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();
}
@Override
protected void finalize() throws Throwable {
super.finalize();
int[] handleArr = new int[] { handle };
glDeleteTextures(1, handleArr, 0);
bitmapCurrentlyUploaded = null;
glExecutor.execute(new Runnable() {
@Override
public void run() {
int[] handleArr = new int[] { handle };
glDeleteTextures(1, handleArr, 0);
}
});
}
private void makeTexture () {
......@@ -77,20 +90,6 @@ public class GLTexture {
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() {
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