diff --git a/Examples/AdvancedEffects/android/app/app.iml b/Examples/AdvancedEffects/android/app/app.iml index 2cd6263fb978920319d5d99a6c685a4ebdea558d..04987cfac2432bef82215719fb37ed437bebb771 100644 --- a/Examples/AdvancedEffects/android/app/app.iml +++ b/Examples/AdvancedEffects/android/app/app.iml @@ -97,8 +97,8 @@ - + diff --git a/Examples/AdvancedEffects/ios/AdvancedEffects.xcodeproj/xcshareddata/xcschemes/AdvancedEffects.xcscheme b/Examples/AdvancedEffects/ios/AdvancedEffects.xcodeproj/xcshareddata/xcschemes/AdvancedEffects.xcscheme index fc0591be51e890b1f2f5a10663f9074f1ca5ee16..0888e641f24af7f6c7e3395348ccfdc64059d77d 100644 --- a/Examples/AdvancedEffects/ios/AdvancedEffects.xcodeproj/xcshareddata/xcschemes/AdvancedEffects.xcscheme +++ b/Examples/AdvancedEffects/ios/AdvancedEffects.xcodeproj/xcshareddata/xcschemes/AdvancedEffects.xcscheme @@ -37,10 +37,10 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -62,15 +62,18 @@ ReferencedContainer = "container:AdvancedEffects.xcodeproj"> + + @@ -82,14 +85,21 @@ ReferencedContainer = "container:AdvancedEffects.xcodeproj"> + + + + diff --git a/Examples/AdvancedEffects/src/Banner.js b/Examples/AdvancedEffects/src/Banner.js index c9f5285f985750ea02c4e0c3a08e52ab28788567..8f412882cd54f98a6ec7f238ed80dfd43428eff0 100644 --- a/Examples/AdvancedEffects/src/Banner.js +++ b/Examples/AdvancedEffects/src/Banner.js @@ -27,7 +27,9 @@ void main( void ) { class Banner extends React.Component { render () { const { width, height, time } = this.props; - return console.log("Banner onLoad")}> + return console.log("Banner onLoad")} + onProgress={e => console.log("Banner onProgress", e.nativeEvent)}> ; } diff --git a/Examples/AdvancedEffects/src/Intro.js b/Examples/AdvancedEffects/src/Intro.js index 662829851bf5a0c7421249dcb69c6aef568bf9c7..94af9f9426b365ec27f90eb672185c6c6971a4fd 100644 --- a/Examples/AdvancedEffects/src/Intro.js +++ b/Examples/AdvancedEffects/src/Intro.js @@ -40,7 +40,9 @@ void main() { class Intro extends React.Component { render () { const { time, fps, width, height } = this.props; - return + return console.log("Intro onLoad")} + onProgress={e => console.log("Intro onProgress", e.nativeEvent)}> true} onMoveShouldSetResponder={() => true} onLoad={() => console.log("Vignette onLoad")} + onProgress={e => console.log("Vignette onProgress", e.nativeEvent)} onResponderMove={this.onResponderMove}> + + + + @@ -77,10 +81,13 @@ + + + diff --git a/Examples/android/RNGL.iml b/Examples/android/RNGL.iml index e3cb714fc579494723124b675e53b2f5c97483d9..d90b763d79676e58f0ed979346315239bc64de94 100644 --- a/Examples/android/RNGL.iml +++ b/Examples/android/RNGL.iml @@ -85,8 +85,8 @@ - + diff --git a/android/RNGL.iml b/android/RNGL.iml index 0ee7994615f51180446a865a16fb4c90840aa6ef..da94af0025670f3a0730de90d6eeb16c76e1ab26 100644 --- a/android/RNGL.iml +++ b/android/RNGL.iml @@ -1,5 +1,5 @@ - + diff --git a/android/src/main/java/com/projectseptember/RNGL/GLCanvas.java b/android/src/main/java/com/projectseptember/RNGL/GLCanvas.java index d7a8919c9317bc34f2faa886f988dc1533ea4189..40cf63cb32ddf32e13148ddd5fcd0e72cad07890 100644 --- a/android/src/main/java/com/projectseptember/RNGL/GLCanvas.java +++ b/android/src/main/java/com/projectseptember/RNGL/GLCanvas.java @@ -33,10 +33,12 @@ import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; +import java.util.Set; import java.util.concurrent.Executor; import javax.microedition.khronos.egl.EGLConfig; @@ -47,7 +49,8 @@ public class GLCanvas extends GLSurfaceView private ReactContext reactContext; private RNGLContext rnglContext; - private boolean preloadingDone = false; + private boolean dirtyOnLoad = true; + private boolean neverRendered = true; private boolean deferredRendering = false; private GLRenderData renderData; private int defaultFBO; @@ -127,11 +130,15 @@ public class GLCanvas extends GLSurfaceView if (contentTextures.size() != this.nbContentTextures) resizeUniformContentTextures(nbContentTextures); - if (!preloadingDone) { - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); + if (haveRemainingToPreload()) { + if (neverRendered) { + neverRendered = false; + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); + } return; } + neverRendered = false; final boolean shouldRenderNow = deferredRendering || autoRedraw || nbContentTextures == 0; if (nbContentTextures > 0) { @@ -161,6 +168,15 @@ public class GLCanvas extends GLSurfaceView } } + private boolean haveRemainingToPreload() { + for (Uri uri: imagesToPreload) { + if (!preloaded.contains(uri)) { + return true; + } + } + return false; + } + public void setNbContentTextures(int n) { this.nbContentTextures = n; requestRender(); @@ -168,7 +184,7 @@ public class GLCanvas extends GLSurfaceView public void setRenderId(int renderId) { if (nbContentTextures > 0) { - if (preloadingDone) syncContentBitmaps(); + if (!haveRemainingToPreload()) syncContentBitmaps(); requestRender(); } } @@ -190,25 +206,18 @@ public class GLCanvas extends GLSurfaceView public void setData (GLData data) { this.data = data; - if (preloadingDone) syncContentBitmaps(); + if (!haveRemainingToPreload()) syncContentBitmaps(); requestSyncData(); } public void setImagesToPreload (ReadableArray imagesToPreloadRA) { - if (preloadingDone) return; List imagesToPreload = new ArrayList<>(); for (int i=0; i images = new HashMap<>(); GLRenderData node = recSyncData(data, images); if (node == null) return false; + Set imagesGone = diff(this.images.keySet(), images.keySet()); renderData = node; this.images = images; + this.preloaded.removeAll(imagesGone); return true; } @@ -652,6 +657,11 @@ public class GLCanvas extends GLSurfaceView recRender(renderData); glDisable(GL_BLEND); glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); + + if (dirtyOnLoad && !haveRemainingToPreload()) { + dirtyOnLoad = false; + dispatchOnLoad(); + } } private void dispatchOnCaptureFrame (String frame) { @@ -666,7 +676,7 @@ public class GLCanvas extends GLSurfaceView private void dispatchOnProgress (double progress, int loaded, int total) { WritableMap event = Arguments.createMap(); - event.putDouble("progress", progress); + event.putDouble("progress", Double.isNaN(progress) ? 0.0 : progress); event.putInt("loaded", loaded); event.putInt("total", total); ReactContext reactContext = (ReactContext)getContext(); @@ -732,4 +742,10 @@ public class GLCanvas extends GLSurfaceView mPointerEvents = pointerEvents; } + static Set diff(Set a, Set b) { + Set d = new HashSet<>(); + d.addAll(a); + d.removeAll(b); + return d; + } } diff --git a/ios/GLCanvas.m b/ios/GLCanvas.m index 2af658374e0cf3b3dce6aa56f9103ba81f2e21d3..9250e7d07092086033f292e987bb5eb31c348382 100644 --- a/ios/GLCanvas.m +++ b/ios/GLCanvas.m @@ -26,6 +26,16 @@ NSString* srcResource (id res) return src; } +NSArray* diff (NSArray* a, NSArray* b) { + NSMutableArray *arr = [[NSMutableArray alloc] init]; + for (NSString* k in a) { + if (![b containsObject:k]) { + [arr addObject:k]; + } + } + return arr; +} + // For reference, see implementation of gl-shader's GLCanvas @implementation GLCanvas @@ -47,7 +57,8 @@ NSString* srcResource (id res) GLint defaultFBO; NSMutableArray *_preloaded; - BOOL _preloadingDone; + BOOL _dirtyOnLoad; + BOOL _neverRendered; NSTimer *animationTimer; @@ -61,7 +72,8 @@ NSString* srcResource (id res) _images = @{}; _preloaded = [[NSMutableArray alloc] init]; _captureFrameRequested = false; - _preloadingDone = false; + _dirtyOnLoad = true; + _neverRendered = true; self.context = [bridge.rnglContext getContext]; self.contentScaleFactor = RCTScreenScale(); } @@ -80,15 +92,8 @@ RCT_NOT_IMPLEMENTED(-init) -(void)setImagesToPreload:(NSArray *)imagesToPreload { - if (_preloadingDone) return; - if ([imagesToPreload count] == 0) { - [self dispatchOnLoad]; - _preloadingDone = true; - } - else { - _preloadingDone = false; - } _imagesToPreload = imagesToPreload; + [self requestSyncData]; } - (void)setOpaque:(BOOL)opaque @@ -151,7 +156,6 @@ RCT_NOT_IMPLEMENTED(-init) - (void)syncData { - [EAGLContext setCurrentContext:self.context]; @autoreleasepool { NSDictionary *prevImages = _images; @@ -270,6 +274,9 @@ RCT_NOT_IMPLEMENTED(-init) if (res != nil) { _renderData = traverseTree(_data); _images = images; + for (NSString *src in diff([prevImages allKeys], [images allKeys])) { + [_preloaded removeObject:src]; + } } } } @@ -303,6 +310,16 @@ RCT_NOT_IMPLEMENTED(-init) } } +- (BOOL)haveRemainingToPreload +{ + for (id res in _imagesToPreload) { + if (![_preloaded containsObject:srcResource(res)]) { + return true; + } + } + return false; +} + //// Draw @@ -316,11 +333,16 @@ RCT_NOT_IMPLEMENTED(-init) self.layer.opaque = _opaque; - if (!_preloadingDone) { - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); + if ([self haveRemainingToPreload]) { + if (_neverRendered) { + _neverRendered = false; + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + } return; } + _neverRendered = false; + BOOL needsDeferredRendering = _nbContentTextures > 0 && !_autoRedraw; if (needsDeferredRendering && !_deferredRendering) { dispatch_async(dispatch_get_main_queue(), ^{ @@ -407,6 +429,11 @@ RCT_NOT_IMPLEMENTED(-init) recDraw(_renderData); glDisable(GL_BLEND); glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); + + if (_dirtyOnLoad && ![self haveRemainingToPreload]) { + _dirtyOnLoad = false; + [self dispatchOnLoad]; + } } } @@ -414,22 +441,13 @@ RCT_NOT_IMPLEMENTED(-init) - (void)onImageLoad:(NSString *)loaded { - if (!_preloadingDone) { - [_preloaded addObject:loaded]; - int count = [self countPreloaded]; - int total = (int) [_imagesToPreload count]; - double progress = ((double) count) / ((double) total); - [self dispatchOnProgress:progress withLoaded:count withTotal:total]; - if (count == total) { - [self dispatchOnLoad]; - _preloadingDone = true; - [self requestSyncData]; - } - } - else { - // Any texture image load will trigger a future re-sync of data (if no preloaded) - [self requestSyncData]; - } + [_preloaded addObject:loaded]; + int count = [self countPreloaded]; + int total = (int) [_imagesToPreload count]; + double progress = ((double) count) / ((double) total); + [self dispatchOnProgress:progress withLoaded:count withTotal:total]; + _dirtyOnLoad = true; + [self requestSyncData]; } - (int)countPreloaded