├── .gitignore ├── README.md ├── babel.config.js ├── lerna.json ├── package.json ├── packages ├── webgltexture-loader-dom-canvas │ ├── .flowconfig │ ├── package.json │ └── src │ │ └── CanvasTextureLoader.js ├── webgltexture-loader-dom-image-url │ ├── .flowconfig │ ├── package.json │ └── src │ │ └── ImageURLTextureLoader.js ├── webgltexture-loader-dom-video │ ├── .flowconfig │ ├── package.json │ └── src │ │ └── VideoTextureLoader.js ├── webgltexture-loader-dom │ ├── .flowconfig │ ├── package.json │ └── src │ │ └── index.js ├── webgltexture-loader-expo-camera │ ├── .flowconfig │ ├── package.json │ └── src │ │ ├── ExpoCameraTextureLoader.js │ │ └── index.js ├── webgltexture-loader-expo │ ├── .flowconfig │ ├── package.json │ └── src │ │ ├── DeprecatedExpoGLObjectTextureLoader.js │ │ ├── ExpoModuleTextureLoader.js │ │ └── index.js ├── webgltexture-loader-ndarray │ ├── .flowconfig │ ├── flow │ │ └── ndarray.js │ ├── package-lock.json │ ├── package.json │ └── src │ │ ├── NDArrayTextureLoader.js │ │ └── drawNDArrayTexture.js ├── webgltexture-loader-react-native-config │ ├── .flowconfig │ ├── package.json │ └── src │ │ └── ConfigTextureLoader.js ├── webgltexture-loader-react-native-imagesource │ ├── .flowconfig │ ├── package.json │ └── src │ │ └── ImageSourceTextureLoader.js ├── webgltexture-loader-react-native │ ├── .flowconfig │ ├── package.json │ └── src │ │ └── index.js └── webgltexture-loader │ ├── .flowconfig │ ├── package.json │ └── src │ ├── LoaderResolver.js │ ├── LoaderResolver.test.js │ ├── LoadersRegistry.js │ ├── WebGLTextureLoader.js │ ├── WebGLTextureLoaderAsyncHashCache.js │ ├── WebGLTextureLoaderAsyncHashCache.test.js │ ├── WebGLTextureLoaderSyncHashCache.js │ ├── WebGLTextureLoaderSyncHashCache.test.js │ ├── globalRegistry.js │ ├── globalRegistry.test.js │ └── index.js ├── scripts └── compile.sh └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | lib/ 3 | coverage/ 4 | lerna-debug.log 5 | .DS_Store 6 | packages/*/README.md 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebGLTextureLoader libraries 2 | 3 | [gre/webgltexture-loader](https://github.com/gre/webgltexture-loader) repository hosts `webgltexture-loader` libraries, utility to load & cache various kind of WebGLTexture with an extensible and loosely coupled system. 4 | 5 | The `webgltexture-loader` library is a core WebGL Texture loader implementation used by frameworks like `gl-react`. 6 | 7 | **The gist** 8 | 9 | > You usually need to build a small helper to hook things together (as things are initially uncoupled). That said, the following gist is a proof it's still viable to directly use it. 10 | 11 | ```js 12 | import { LoaderResolver } from "webgltexture-loader"; 13 | import "webgltexture-loader-dom"; // import support for DOM, including video, canvas or simple image url 14 | 15 | const canvas = document.createElement("canvas"); document.body.appendChild(canvas); 16 | const gl = canvas.getContext("webgl"); 17 | 18 | const resolver = new LoaderResolver(gl); 19 | 20 | function load (input) { // just an example (create your own load function based on needs) 21 | const loader = resolver.resolve(input); 22 | return loader ? loader.load(input) : Promise.reject("no loader supports the input "+input); 23 | } 24 | 25 | load("https://i.imgur.com/wxqlQkh.jpg") // just an example, many format supported here 26 | .then(({ texture }) => { 27 | const program = createDemoProgram(gl); 28 | const tLocation = gl.getUniformLocation(program, "t"); 29 | gl.activeTexture(gl.TEXTURE0); 30 | gl.bindTexture(gl.TEXTURE_2D, texture); 31 | gl.uniform1i(tLocation, 0); 32 | gl.drawArrays(gl.TRIANGLES, 0, 3); 33 | }); 34 | ``` 35 | 36 | [createDemoProgram() source code](https://gist.github.com/gre/5d894656e10c70409b9e60e265753e94) 37 | 38 | ## WebGLTextureLoader ? 39 | 40 | a `WebGLTextureLoader` is an object created with a `WebGLRenderingContext` that can load and cache a WebGLTexture for a given input. 41 | 42 | ```js 43 | type TextureAndSize = { 44 | texture: WebGLTexture, 45 | width: number, 46 | height: number 47 | } 48 | 49 | class WebGLTextureLoader { 50 | constructor(gl: WebGLRenderingContext){} 51 | canLoad(input: any): boolean 52 | load(input: T): Promise 53 | get(input: T): ?TextureAndSize 54 | update(input: T) 55 | } 56 | ``` 57 | 58 | 59 | If `loader.canLoad(input)` is true, the loader can be used: 60 | 61 | `loader.get(input)` returns a **{texture, width, height}** object if the input is loaded. Otherwise it returns null, and you need to call `loader.load(input)` to load the resource, which return a promise of that same object. Note that you can just stick with the `load` API. 62 | 63 | > When the load(input) promise is fulfilled, it is guarantee that `loader.get(input)` returns a result that is `===` to the Promise result. It is also guarantee that 2 call to the same `loader.load(input)` is idempotent and returns the same Promise (by `===`). 64 | 65 | ### Why is there both `get` and `load` API? 66 | 67 | The dual `get` and `load` is defined to allow the best of the 2 worlds paradigms: async and sync. Typically, you can call `get()` in a requestAnimationFrame loop (and call load if it fails so the future frames will eventually have it resolved). But, in a more async paradigm, you can wait the `load()` Promise. 68 | 69 | A second reason is that some Loader are simply sync by nature. For instance, the HTMLCanvasElement or ndarray loaders. (this is transparent when using the API). 70 | 71 | Th idea behind `get(input)` is also to allow functional/"descriptive" way like an object coming from React (e.g. in React, user sent again and again the full state tree and therefore don't keep state, input might just be an new object each time, the library do the reconciliation in some way). 72 | 73 | ## LoaderResolver 74 | 75 | A LoaderResolver is a tiny utility that instantiate the loaders and exposes a resolve method that returns the first WebGLTextureLoader that `canLoad` a given input. 76 | 77 | ```js 78 | const resolver = new LoaderResolver(gl); // instantiate once 79 | const maybeLoader = resolver.resolve(input); // use many times 80 | // then do your logic... 81 | // ... maybeLoader.get(input); 82 | // ... maybeLoader.load(input); 83 | ``` 84 | 85 | > `LoaderResolver` also accept a second parameter that is the LoadersRegistry to use, by default it is the "globalRegistry". 86 | 87 | ## Available loaders 88 | 89 | Loaders implementation are available via various NPM packages. The idea of each is that they both expose the loader class but they will also automatically add itself in the globalRegistry (as soon as imported in the bundle). So typically you need to `import "webgltexture-loader-WHATEVER;"` them all and use `new LoaderResolver(gl)` to use the globalRegistry. 90 | 91 | - `webgltexture-loader-dom` add all **DOM only** loaders: 92 | - `webgltexture-loader-dom-canvas` for a HTMLCanvasElement 93 | - `webgltexture-loader-dom-video` for a HTMLVideoElement 94 | - `webgltexture-loader-dom-image-url` support for image by giving it's URL (as a string input). 95 | - `webgltexture-loader-ndarray` add **NDArray loader** support. 96 | - `webgltexture-loader-react-native` add all **React Native** loaders (using react-native-webgl) 97 | - `webgltexture-loader-react-native-config` add the generic Config format of react-native-webgl 98 | - `webgltexture-loader-react-native-imagesource` add support of ImageSource (same format as in React Native Image source prop). 99 | - `webgltexture-loader-expo` exposes loaders for Expo (EXGLView). They might soon be replaced by `webgltexture-loader-react-native` if it gets migrated to react-native-webgl. 100 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | "@babel/env", 5 | { 6 | targets: { 7 | browsers: "Last 2 Chrome versions, Firefox ESR", 8 | node: "current" 9 | } 10 | } 11 | ], 12 | "@babel/preset-flow" 13 | ], 14 | plugins: [ 15 | "@babel/plugin-proposal-class-properties", 16 | "@babel/plugin-proposal-object-rest-spread" 17 | ] 18 | }; 19 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "3.16.4", 3 | "packages": [ 4 | "packages/*" 5 | ], 6 | "version": "2.0.0", 7 | "npmClient": "yarn", 8 | "useWorkspaces": true 9 | } 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "webgltexture-loader-libs", 4 | "version": "0.0.0", 5 | "workspaces": [ 6 | "packages/*" 7 | ], 8 | "description": "Generic & extensible texture loader utility", 9 | "main": "lib/index.js", 10 | "files": [ 11 | "src", 12 | "lib" 13 | ], 14 | "repository": "https://github.com/gre/webgltexture-loader", 15 | "author": "Gaëtan Renaudeau ", 16 | "license": "MIT", 17 | "devDependencies": { 18 | "@babel/cli": "^7.14.3", 19 | "@babel/plugin-proposal-class-properties": "^7.13.0", 20 | "@babel/plugin-proposal-object-rest-spread": "^7.14.4", 21 | "@babel/preset-env": "^7.14.4", 22 | "@babel/preset-flow": "^7.13.13", 23 | "babel-jest": "28.1.0", 24 | "flow-copy-source": "2.0.9", 25 | "jest": "28.1.0", 26 | "lerna": "^3.22.1" 27 | }, 28 | "scripts": { 29 | "preinstall": "node -e \"if (process.env.npm_execpath.indexOf('yarn') === -1) { console.log('\u001b[31mPlease use yarn\u001b[0m'); process.exit(1); }\"", 30 | "test": "jest", 31 | "build": "./scripts/compile.sh", 32 | "publish": "npm run build && lerna publish" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-dom-canvas/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | 7 | [options] 8 | 9 | [lints] 10 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-dom-canvas/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webgltexture-loader-dom-canvas", 3 | "version": "2.0.0", 4 | "description": "HTMLCanvasElement loader for webgltexture-loader", 5 | "main": "lib/CanvasTextureLoader.js", 6 | "files": [ 7 | "src", 8 | "lib" 9 | ], 10 | "repository": "https://github.com/gre/webgltexture-loader", 11 | "author": "Gaëtan Renaudeau ", 12 | "license": "MIT", 13 | "dependencies": { 14 | "webgltexture-loader": "^2.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-dom-canvas/src/CanvasTextureLoader.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import { 3 | WebGLTextureLoaderSyncHashCache, 4 | globalRegistry 5 | } from "webgltexture-loader"; 6 | 7 | class CanvasTextureLoader extends WebGLTextureLoaderSyncHashCache< 8 | HTMLCanvasElement 9 | > { 10 | disposes = {}; 11 | 12 | canLoad(input: any) { 13 | return input instanceof HTMLCanvasElement; 14 | } 15 | 16 | inputHash(input: HTMLCanvasElement) { 17 | return input; 18 | } 19 | 20 | getNoCache(input: HTMLCanvasElement) { 21 | const { gl } = this; 22 | const { width, height } = input; 23 | const texture = gl.createTexture(); 24 | gl.bindTexture(gl.TEXTURE_2D, texture); 25 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, input); 26 | return { texture, width, height }; 27 | } 28 | 29 | update(input: HTMLCanvasElement) { 30 | const { gl } = this; 31 | const { texture } = this.get(input); 32 | gl.bindTexture(gl.TEXTURE_2D, texture); 33 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, input); 34 | } 35 | } 36 | 37 | globalRegistry.add(CanvasTextureLoader); 38 | 39 | export default CanvasTextureLoader; 40 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-dom-image-url/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | 7 | [options] 8 | 9 | [lints] 10 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-dom-image-url/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webgltexture-loader-dom-image-url", 3 | "version": "2.0.0", 4 | "description": "load an Image by its URL for webgltexture-loader", 5 | "main": "lib/ImageURLTextureLoader.js", 6 | "files": [ 7 | "src", 8 | "lib" 9 | ], 10 | "repository": "https://github.com/gre/webgltexture-loader", 11 | "author": "Gaëtan Renaudeau ", 12 | "license": "MIT", 13 | "dependencies": { 14 | "webgltexture-loader": "^2.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-dom-image-url/src/ImageURLTextureLoader.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import { 3 | globalRegistry, 4 | WebGLTextureLoaderAsyncHashCache 5 | } from "webgltexture-loader"; 6 | 7 | function loadImage( 8 | src: string, 9 | success: (img: Image) => void, 10 | failure: (e: Error) => void 11 | ) { 12 | let img = new window.Image(); 13 | if (src.slice(0, 5) !== "data:") { 14 | img.crossOrigin = true; 15 | } 16 | img.onload = function() { 17 | if (img) { 18 | success(img); 19 | } 20 | img = null; 21 | }; 22 | img.onabort = img.onerror = failure; 23 | img.src = src; 24 | return function() { 25 | if (img) { 26 | img.onload = null; 27 | img.onerror = null; 28 | img.onabort = null; 29 | img.src = ""; 30 | img = null; 31 | } 32 | }; 33 | } 34 | class ImageURLTextureLoader extends WebGLTextureLoaderAsyncHashCache { 35 | canLoad(input: any) { 36 | return typeof input === "string"; 37 | } 38 | 39 | inputHash(input: string) { 40 | return input; 41 | } 42 | 43 | loadNoCache(src: string) { 44 | const { gl } = this; 45 | let dispose; 46 | const promise = new Promise( 47 | (success, failure) => (dispose = loadImage(src, success, failure)) 48 | ).then(img => { 49 | const { width, height } = img; 50 | const texture = gl.createTexture(); 51 | gl.bindTexture(gl.TEXTURE_2D, texture); 52 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img); 53 | return { texture, width, height }; 54 | }); 55 | return { promise, dispose: () => dispose() }; 56 | } 57 | } 58 | 59 | globalRegistry.add(ImageURLTextureLoader); 60 | 61 | export default ImageURLTextureLoader; 62 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-dom-video/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | 7 | [options] 8 | 9 | [lints] 10 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-dom-video/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webgltexture-loader-dom-video", 3 | "version": "2.0.0", 4 | "description": "HTMLVideoElement loader for webgltexture-loader", 5 | "main": "lib/VideoTextureLoader.js", 6 | "files": [ 7 | "src", 8 | "lib" 9 | ], 10 | "repository": "https://github.com/gre/webgltexture-loader", 11 | "author": "Gaëtan Renaudeau ", 12 | "license": "MIT", 13 | "dependencies": { 14 | "webgltexture-loader": "^2.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-dom-video/src/VideoTextureLoader.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import { 3 | WebGLTextureLoaderAsyncHashCache, 4 | globalRegistry 5 | } from "webgltexture-loader"; 6 | 7 | class VideoTextureLoader extends WebGLTextureLoaderAsyncHashCache< 8 | HTMLVideoElement 9 | > { 10 | canLoad(input: any) { 11 | return input instanceof HTMLVideoElement; 12 | } 13 | 14 | inputHash(input: HTMLVideoElement) { 15 | return input; 16 | } 17 | 18 | loadNoCache(input: HTMLVideoElement) { 19 | const { gl } = this; 20 | const { width, height } = input; 21 | 22 | let timeout; 23 | const dispose = () => { 24 | clearTimeout(timeout); 25 | }; 26 | 27 | const promise = new Promise((resolve, reject) => { 28 | const checkVideoReady = () => { 29 | if (input.videoWidth > 0) { 30 | const texture = gl.createTexture(); 31 | const { videoWidth: width, videoHeight: height } = input; 32 | gl.bindTexture(gl.TEXTURE_2D, texture); 33 | gl.texImage2D( 34 | gl.TEXTURE_2D, 35 | 0, 36 | gl.RGBA, 37 | gl.RGBA, 38 | gl.UNSIGNED_BYTE, 39 | input 40 | ); 41 | resolve({ 42 | texture, 43 | width, 44 | height 45 | }); 46 | } else { 47 | timeout = setTimeout(checkVideoReady, 100); 48 | } 49 | }; 50 | checkVideoReady(); 51 | }); 52 | 53 | return { dispose, promise }; 54 | } 55 | 56 | update(input: HTMLVideoElement) { 57 | const { gl } = this; 58 | const res = this.get(input); 59 | if (!res) return; 60 | gl.bindTexture(gl.TEXTURE_2D, res.texture); 61 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, input); 62 | } 63 | } 64 | 65 | globalRegistry.add(VideoTextureLoader); 66 | 67 | export default VideoTextureLoader; 68 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-dom/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | 7 | [options] 8 | 9 | [lints] 10 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-dom/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webgltexture-loader-dom", 3 | "version": "2.0.0", 4 | "description": "collection of webgltexture-loader in DOM implementation context", 5 | "main": "lib/index.js", 6 | "files": [ 7 | "src", 8 | "lib" 9 | ], 10 | "repository": "https://github.com/gre/webgltexture-loader", 11 | "author": "Gaëtan Renaudeau ", 12 | "license": "MIT", 13 | "dependencies": { 14 | "webgltexture-loader-dom-canvas": "^2.0.0", 15 | "webgltexture-loader-dom-image-url": "^2.0.0", 16 | "webgltexture-loader-dom-video": "^2.0.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-dom/src/index.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import CanvasTextureLoader from "webgltexture-loader-dom-canvas"; 3 | import VideoTextureLoader from "webgltexture-loader-dom-video"; 4 | import ImageURLTextureLoader from "webgltexture-loader-dom-image-url"; 5 | 6 | export { CanvasTextureLoader, VideoTextureLoader, ImageURLTextureLoader }; 7 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-expo-camera/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | 7 | [options] 8 | 9 | [lints] 10 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-expo-camera/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webgltexture-loader-expo-camera", 3 | "version": "2.0.0", 4 | "description": "load camera expo 'config' object for webgltexture-loader", 5 | "main": "lib/index.js", 6 | "files": [ 7 | "src", 8 | "lib" 9 | ], 10 | "repository": "https://github.com/gre/webgltexture-loader", 11 | "author": "Gaëtan Renaudeau ", 12 | "license": "MIT", 13 | "peerDependencies": { 14 | "expo-camera": "*", 15 | "expo-modules-core": "*", 16 | "react-native": "*" 17 | }, 18 | "dependencies": { 19 | "webgltexture-loader": "^2.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-expo-camera/src/ExpoCameraTextureLoader.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import { 3 | globalRegistry, 4 | WebGLTextureLoaderAsyncHashCache 5 | } from "webgltexture-loader"; 6 | import { findNodeHandle } from "react-native"; 7 | import { NativeModulesProxy } from "expo-modules-core"; 8 | import { Camera } from "expo-camera"; 9 | 10 | const neverEnding = new Promise(() => { }); 11 | 12 | const available = !!( 13 | NativeModulesProxy.ExponentGLObjectManager && 14 | NativeModulesProxy.ExponentGLObjectManager.createCameraTextureAsync 15 | ); 16 | 17 | let warned = false; 18 | 19 | class ExpoCameraTextureLoader extends WebGLTextureLoaderAsyncHashCache { 20 | static priority = -199; 21 | 22 | objIds: WeakMap = new WeakMap(); 23 | 24 | canLoad(input: any) { 25 | if (input && input instanceof Camera) { 26 | if (available) return true; 27 | if (!warned) { 28 | warned = true; 29 | console.log( 30 | "webgltexture-loader-expo: ExponentGLObjectManager.createCameraTextureAsync is not available. Make sure to use the correct version of Expo" 31 | ); 32 | } 33 | } 34 | return false; 35 | } 36 | 37 | disposeTexture(texture: WebGLTexture) { 38 | const exglObjId = this.objIds.get(texture); 39 | if (exglObjId) { 40 | NativeModulesProxy.ExponentGLObjectManager.destroyObjectAsync(exglObjId); 41 | } 42 | this.objIds.delete(texture); 43 | } 44 | 45 | inputHash(camera: Camera) { 46 | return findNodeHandle(camera); 47 | } 48 | 49 | loadNoCache(camera: Camera) { 50 | const { gl } = this; 51 | // $FlowFixMe 52 | const { __exglCtxId: exglCtxId } = gl; 53 | let disposed = false; 54 | const dispose = () => { 55 | disposed = true; 56 | }; 57 | const glView = gl.getExtension("GLViewRef"); 58 | const promise: Promise<*> = !glView 59 | ? Promise.reject(new Error("GLViewRef not available")) 60 | : glView.createCameraTextureAsync(camera).then(texture => { 61 | if (disposed) return neverEnding; 62 | // $FlowFixMe 63 | this.objIds.set(texture, texture.exglObjId); 64 | const width = 0; 65 | const height = 0; 66 | // ^ any way to retrieve these ? 67 | return { texture, width, height }; 68 | }); 69 | return { promise, dispose }; 70 | } 71 | } 72 | 73 | globalRegistry.add(ExpoCameraTextureLoader); 74 | 75 | export default ExpoCameraTextureLoader; 76 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-expo-camera/src/index.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import ExpoCameraTextureLoader from "./ExpoCameraTextureLoader"; 3 | 4 | export { ExpoCameraTextureLoader }; 5 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-expo/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | 7 | [options] 8 | 9 | [lints] 10 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-expo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webgltexture-loader-expo", 3 | "version": "2.0.0", 4 | "description": "load basic expo 'config' object for webgltexture-loader", 5 | "main": "lib/index.js", 6 | "files": [ 7 | "src", 8 | "lib" 9 | ], 10 | "repository": "https://github.com/gre/webgltexture-loader", 11 | "author": "Gaëtan Renaudeau ", 12 | "license": "MIT", 13 | "peerDependencies": { 14 | "expo-modules-core": "*", 15 | "react-native": "*" 16 | }, 17 | "dependencies": { 18 | "expo-asset-utils": "^3.0.0", 19 | "webgltexture-loader": "^2.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-expo/src/DeprecatedExpoGLObjectTextureLoader.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import { 3 | globalRegistry, 4 | WebGLTextureLoaderAsyncHashCache 5 | } from "webgltexture-loader"; 6 | import { NativeModulesProxy } from "expo-modules-core"; 7 | 8 | const neverEnding = new Promise(() => { }); 9 | 10 | const available = !!( 11 | NativeModulesProxy.ExponentGLObjectManager && 12 | NativeModulesProxy.ExponentGLObjectManager.createObjectAsync 13 | ); 14 | 15 | let warned = false; 16 | 17 | class ExpoGLObjectTextureLoader extends WebGLTextureLoaderAsyncHashCache { 18 | static priority = -200; 19 | 20 | objIds: WeakMap = new WeakMap(); 21 | 22 | canLoad(input: any) { 23 | if (!available && !warned) { 24 | warned = true; 25 | console.log( 26 | "webgltexture-loader-expo: ExponentGLObjectManager.createObjectAsync is not available. Make sure to use the correct version of Expo" 27 | ); 28 | } 29 | return available && typeof input === "object"; 30 | } 31 | 32 | disposeTexture(texture: WebGLTexture) { 33 | const exglObjId = this.objIds.get(texture); 34 | if (exglObjId) { 35 | NativeModulesProxy.ExponentGLObjectManager.destroyObjectAsync(exglObjId); 36 | } 37 | this.objIds.delete(texture); 38 | } 39 | 40 | inputHash(config: Object) { 41 | // JSON.stringify is a quick way to hash the config object 42 | return JSON.stringify(config); 43 | } 44 | 45 | loadNoCache(config: Object) { 46 | const { gl } = this; 47 | // $FlowFixMe 48 | const { __exglCtxId: exglCtxId } = gl; 49 | let disposed = false; 50 | const dispose = () => { 51 | disposed = true; 52 | }; 53 | const promise = NativeModulesProxy.ExponentGLObjectManager.createObjectAsync( 54 | { 55 | exglCtxId, 56 | texture: config 57 | } 58 | ).then(({ exglObjId }) => { 59 | if (disposed) return neverEnding; 60 | // $FlowFixMe 61 | const texture = new WebGLTexture(exglObjId); 62 | this.objIds.set(texture, exglObjId); 63 | const width = 0; 64 | const height = 0; 65 | // ^ unfortunately there is no way to retrieve these 66 | return { texture, width, height }; 67 | }); 68 | return { promise, dispose }; 69 | } 70 | } 71 | 72 | globalRegistry.add(ExpoGLObjectTextureLoader); 73 | 74 | export default ExpoGLObjectTextureLoader; 75 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-expo/src/ExpoModuleTextureLoader.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import { 3 | globalRegistry, 4 | WebGLTextureLoaderAsyncHashCache, 5 | } from "webgltexture-loader"; 6 | import * as AssetUtils from "expo-asset-utils"; 7 | import { Asset } from "expo-asset"; 8 | 9 | const neverEnding = new Promise(() => {}); 10 | 11 | const localAsset = (module: number) => { 12 | const asset = Asset.fromModule(module); 13 | return asset.downloadAsync().then(() => asset); 14 | }; 15 | 16 | type AssetModel = { 17 | width: number, 18 | height: number, 19 | uri: string, 20 | localUri: string, 21 | }; 22 | 23 | type M = number | { uri: string } | AssetModel; 24 | 25 | export const loadAsset = (module: M): Promise => 26 | typeof module === "number" 27 | ? localAsset(module) 28 | : module.localUri 29 | ? // $FlowFixMe 30 | Promise.resolve(module) 31 | : AssetUtils.resolveAsync(module.uri); 32 | 33 | class ExpoModuleTextureLoader extends WebGLTextureLoaderAsyncHashCache { 34 | objIds: WeakMap = new WeakMap(); 35 | 36 | canLoad(input: any) { 37 | return ( 38 | typeof input === "number" || 39 | (input && typeof input === "object" && typeof input.uri === "string") 40 | ); 41 | } 42 | 43 | inputHash(module: *) { 44 | return typeof module === "number" ? module : module.uri; 45 | } 46 | 47 | loadNoCache(module: *) { 48 | const { gl } = this; 49 | let disposed = false; 50 | const dispose = () => { 51 | disposed = true; 52 | }; 53 | const promise = loadAsset(module).then((asset) => { 54 | if (disposed) return neverEnding; 55 | const { width, height } = asset; 56 | const texture = gl.createTexture(); 57 | gl.bindTexture(gl.TEXTURE_2D, texture); 58 | gl.texImage2D( 59 | gl.TEXTURE_2D, 60 | 0, 61 | gl.RGBA, 62 | width, 63 | height, 64 | 0, 65 | gl.RGBA, 66 | gl.UNSIGNED_BYTE, 67 | asset 68 | ); 69 | return { texture, width, height }; 70 | }); 71 | return { promise, dispose }; 72 | } 73 | } 74 | 75 | globalRegistry.add(ExpoModuleTextureLoader); 76 | 77 | export default ExpoModuleTextureLoader; 78 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-expo/src/index.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import DeprecatedExpoGLObjectTextureLoader from "./DeprecatedExpoGLObjectTextureLoader"; 3 | import ExpoModuleTextureLoader from "./ExpoModuleTextureLoader"; 4 | export { DeprecatedExpoGLObjectTextureLoader, ExpoModuleTextureLoader }; 5 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-ndarray/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | flow/ 7 | 8 | [options] 9 | 10 | [lints] 11 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-ndarray/flow/ndarray.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | 3 | /** 4 | * Multidimensional Arrays object from library 5 | * [ndarray](https://www.npmjs.com/package/ndarray) 6 | */ 7 | type NDArray = { 8 | shape: Array, 9 | data: $TypedArray | Array, 10 | stride: Array, 11 | offset: number, 12 | size: Array, 13 | order: Array, 14 | dimension: number, 15 | transpose: (...args: Array) => NDArray, 16 | step: (...args: Array) => NDArray, 17 | lo: (...args: Array) => NDArray, 18 | hi: (...args: Array) => NDArray, 19 | pick: (...args: Array) => * 20 | }; 21 | 22 | declare module "ndarray" { 23 | declare type NDArray = NDArray; 24 | declare var exports: ( 25 | arr: $TypedArray | Array, 26 | shape?: Array, 27 | stride?: Array, 28 | offset?: number 29 | ) => NDArray; 30 | } 31 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-ndarray/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "bit-twiddle": { 6 | "version": "1.0.2", 7 | "resolved": "https://registry.npmjs.org/bit-twiddle/-/bit-twiddle-1.0.2.tgz", 8 | "integrity": "sha1-DGwfq+KyPRcXPZpht7cJPrnhdp4=" 9 | }, 10 | "cwise-compiler": { 11 | "version": "1.1.3", 12 | "resolved": "https://registry.npmjs.org/cwise-compiler/-/cwise-compiler-1.1.3.tgz", 13 | "integrity": "sha1-9NZnQQ6FDToxOn0tt7HlBbsDTMU=", 14 | "requires": { 15 | "uniq": "1.0.1" 16 | } 17 | }, 18 | "dup": { 19 | "version": "1.0.0", 20 | "resolved": "https://registry.npmjs.org/dup/-/dup-1.0.0.tgz", 21 | "integrity": "sha1-UfxaxoX4GWRp3wuQXpNLIK9bQCk=" 22 | }, 23 | "iota-array": { 24 | "version": "1.0.0", 25 | "resolved": "https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz", 26 | "integrity": "sha1-ge9X/l0FgUzVjCSDYyqZwwoOgIc=" 27 | }, 28 | "is-buffer": { 29 | "version": "1.1.6", 30 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 31 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" 32 | }, 33 | "ndarray": { 34 | "version": "1.0.18", 35 | "resolved": "https://registry.npmjs.org/ndarray/-/ndarray-1.0.18.tgz", 36 | "integrity": "sha1-tg06cyJOxVXQ+qeXEeUCRI/T95M=", 37 | "requires": { 38 | "iota-array": "1.0.0", 39 | "is-buffer": "1.1.6" 40 | } 41 | }, 42 | "ndarray-ops": { 43 | "version": "1.2.2", 44 | "resolved": "https://registry.npmjs.org/ndarray-ops/-/ndarray-ops-1.2.2.tgz", 45 | "integrity": "sha1-WeiNLDKn7ryxvGkPrhQVeVV6YU4=", 46 | "requires": { 47 | "cwise-compiler": "1.1.3" 48 | } 49 | }, 50 | "typedarray-pool": { 51 | "version": "1.1.0", 52 | "resolved": "https://registry.npmjs.org/typedarray-pool/-/typedarray-pool-1.1.0.tgz", 53 | "integrity": "sha1-0RT0hIAUifU+yrXoCIqiMET0mNk=", 54 | "requires": { 55 | "bit-twiddle": "1.0.2", 56 | "dup": "1.0.0" 57 | } 58 | }, 59 | "uniq": { 60 | "version": "1.0.1", 61 | "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", 62 | "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" 63 | } 64 | }, 65 | "version": "2.0.0" 66 | } 67 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-ndarray/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webgltexture-loader-ndarray", 3 | "version": "2.0.0", 4 | "description": "ndarray loader for webgltexture-loader", 5 | "main": "lib/NDArrayTextureLoader.js", 6 | "files": [ 7 | "src", 8 | "lib" 9 | ], 10 | "repository": "https://github.com/gre/webgltexture-loader", 11 | "author": "Gaëtan Renaudeau ", 12 | "license": "MIT", 13 | "dependencies": { 14 | "ndarray": "^1.0.19", 15 | "ndarray-ops": "^1.2.2", 16 | "typedarray-pool": "^1.2.0", 17 | "webgltexture-loader": "^2.0.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-ndarray/src/NDArrayTextureLoader.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import { 3 | WebGLTextureLoaderSyncHashCache, 4 | globalRegistry, 5 | } from "webgltexture-loader"; 6 | import type { NDArray } from "ndarray"; 7 | import drawNDArrayTexture from "./drawNDArrayTexture"; 8 | 9 | class NDArrayTextureLoader extends WebGLTextureLoaderSyncHashCache { 10 | floatSupported: boolean; 11 | constructor(gl: *) { 12 | super(gl); 13 | this.floatSupported = gl.getExtension("OES_texture_float_linear"); 14 | } 15 | 16 | canLoad(obj: any) { 17 | return obj.shape && obj.data && obj.stride; 18 | } 19 | 20 | inputHash(input: NDArray) { 21 | return input; 22 | } 23 | 24 | getNoCache(input: NDArray) { 25 | const { gl } = this; 26 | const texture = gl.createTexture(); 27 | gl.bindTexture(gl.TEXTURE_2D, texture); 28 | const [width, height] = input.shape; 29 | drawNDArrayTexture(gl, texture, input, this.floatSupported); 30 | return { texture, width, height }; 31 | } 32 | 33 | update(input: NDArray) { 34 | // For now we assume the NDArray always change & need a redraw but we might try to only update if changes later 35 | const { gl } = this; 36 | const { texture } = this.get(input); 37 | gl.bindTexture(gl.TEXTURE_2D, texture); 38 | drawNDArrayTexture(gl, texture, input, this.floatSupported); 39 | } 40 | } 41 | 42 | globalRegistry.add(NDArrayTextureLoader); 43 | 44 | export default NDArrayTextureLoader; 45 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-ndarray/src/drawNDArrayTexture.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import type { NDArray } from "ndarray"; 3 | import ndarray from "ndarray"; 4 | import ops from "ndarray-ops"; 5 | import pool from "typedarray-pool"; 6 | 7 | if (typeof Buffer === "undefined") { 8 | global.Buffer = class Buffer { 9 | // mock shim so pool don't crash.. 10 | static isBuffer = (b) => b instanceof Buffer; 11 | }; 12 | } 13 | 14 | // code is partly taken from https://github.com/stackgl/gl-texture2d/blob/master/texture.js 15 | 16 | function isPacked(shape, stride) { 17 | if (shape.length === 3) { 18 | return ( 19 | stride[2] === 1 && 20 | stride[1] === shape[0] * shape[2] && 21 | stride[0] === shape[2] 22 | ); 23 | } 24 | return stride[0] === 1 && stride[1] === shape[0]; 25 | } 26 | 27 | function convertFloatToUint8(out, inp) { 28 | ops.muls(out, inp, 255.0); 29 | } 30 | 31 | export default ( 32 | gl: WebGLRenderingContext, 33 | texture: WebGLTexture, 34 | array: NDArray, 35 | floatSupported: boolean 36 | ) => { 37 | const isWebGL1 = 38 | typeof WebGLRenderingContext === "undefined" || 39 | gl instanceof WebGLRenderingContext; 40 | 41 | let dtype = array.dtype; 42 | let shape = array.shape.slice(); 43 | let maxSize = gl.getParameter(gl.MAX_TEXTURE_SIZE); 44 | if ( 45 | shape[0] < 0 || 46 | shape[0] > maxSize || 47 | shape[1] < 0 || 48 | shape[1] > maxSize 49 | ) { 50 | throw new Error("gl-react: Invalid texture size"); 51 | } 52 | let packed = isPacked(shape, array.stride.slice()); 53 | let type = 0; 54 | if (dtype === "float32") { 55 | type = gl.FLOAT; 56 | } else if (dtype === "float64") { 57 | type = gl.FLOAT; 58 | packed = false; 59 | dtype = "float32"; 60 | } else if (dtype === "uint8") { 61 | type = gl.UNSIGNED_BYTE; 62 | } else { 63 | type = gl.UNSIGNED_BYTE; 64 | packed = false; 65 | dtype = "uint8"; 66 | } 67 | let format = 0; 68 | let internalformat = 0; 69 | if (shape.length === 2) { 70 | internalformat = format = gl.LUMINANCE; 71 | shape = [shape[0], shape[1], 1]; 72 | array = ndarray( 73 | array.data, 74 | shape, 75 | [array.stride[0], array.stride[1], 1], 76 | array.offset 77 | ); 78 | } else if (shape.length === 3) { 79 | if (shape[2] === 1) { 80 | internalformat = format = gl.ALPHA; 81 | if (!isWebGL1) { 82 | floatSupported = false; // eject from WebGL2 because it seems not to correctly have a internalfomat for this. need to use uint8 83 | } 84 | } else if (shape[2] === 2) { 85 | internalformat = format = gl.LUMINANCE_ALPHA; 86 | if (!isWebGL1) { 87 | floatSupported = false; // eject from WebGL2 because it seems not to correctly have a internalfomat for this. need to use uint8 88 | } 89 | } else if (shape[2] === 3) { 90 | format = gl.RGB; 91 | internalformat = isWebGL1 ? gl.RGB : gl.RGB32F; 92 | } else if (shape[2] === 4) { 93 | format = gl.RGBA; 94 | internalformat = isWebGL1 ? gl.RGBA : gl.RGBA32F; 95 | } else { 96 | throw new Error("gl-texture2d: Invalid shape for pixel coords"); 97 | } 98 | } else { 99 | throw new Error("gl-texture2d: Invalid shape for texture"); 100 | } 101 | if (type === gl.FLOAT && !floatSupported) { 102 | type = gl.UNSIGNED_BYTE; 103 | packed = false; 104 | } 105 | let buffer; 106 | let size = array.size; 107 | let store; 108 | if (!packed) { 109 | let stride = [shape[2], shape[2] * shape[0], 1]; 110 | if ( 111 | (dtype === "float32" || dtype === "float64") && 112 | type === gl.UNSIGNED_BYTE 113 | ) { 114 | store = pool.malloc(size, "uint8"); 115 | let out = ndarray(store, shape, stride, 0); 116 | convertFloatToUint8(out, array); 117 | } else { 118 | store = pool.malloc(size, dtype); 119 | let out = ndarray(store, shape, stride, 0); 120 | ops.assign(out, array); 121 | } 122 | buffer = store.subarray(0, size); 123 | } else if (array.offset === 0 && array.data.length === size) { 124 | buffer = array.data; 125 | } else { 126 | buffer = array.data.subarray(array.offset, array.offset + size); 127 | } 128 | gl.texImage2D( 129 | gl.TEXTURE_2D, 130 | 0, 131 | internalformat, 132 | shape[0], 133 | shape[1], 134 | 0, 135 | format, 136 | type, 137 | buffer 138 | ); 139 | if (store) { 140 | pool.free(store); 141 | } 142 | }; 143 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-react-native-config/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | 7 | [options] 8 | 9 | [lints] 10 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-react-native-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webgltexture-loader-react-native-config", 3 | "version": "2.0.0", 4 | "description": "load any react-native-webgl 'config' object for webgltexture-loader", 5 | "main": "lib/ConfigTextureLoader.js", 6 | "files": [ 7 | "src", 8 | "lib" 9 | ], 10 | "repository": "https://github.com/gre/webgltexture-loader", 11 | "author": "Gaëtan Renaudeau ", 12 | "license": "MIT", 13 | "dependencies": { 14 | "webgltexture-loader": "^2.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-react-native-config/src/ConfigTextureLoader.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import { 3 | globalRegistry, 4 | WebGLTextureLoaderAsyncHashCache 5 | } from "webgltexture-loader"; 6 | 7 | type Config = Object; 8 | 9 | class ConfigTextureLoader extends WebGLTextureLoaderAsyncHashCache { 10 | static priority = -100; // this loader accept any config object, so we need a low priority to make this a "last loader" fallback. we might later improve the granularity (making this paradigm first citizen in react-native-webgl?) 11 | 12 | rngl = this.gl.getExtension("RN"); 13 | 14 | canLoad(input: any) { 15 | return typeof input === "object"; // technically any config object is possible, so we'll make sure to use a low priority 16 | } 17 | 18 | disposeTexture(texture: WebGLTexture) { 19 | this.rngl.unloadTexture(texture); 20 | } 21 | 22 | inputHash(config: Config) { 23 | // JSON.stringify is a quick way to hash the config object 24 | return JSON.stringify(config); 25 | } 26 | 27 | loadNoCache(config: Config) { 28 | const promise = this.rngl.loadTexture(config); 29 | const dispose = () => { 30 | // FIXME not sure what we can do for now 31 | }; 32 | return { promise, dispose }; 33 | } 34 | } 35 | 36 | globalRegistry.add(ConfigTextureLoader); 37 | 38 | export default ConfigTextureLoader; 39 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-react-native-imagesource/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | 7 | [options] 8 | 9 | [lints] 10 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-react-native-imagesource/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webgltexture-loader-react-native-imagesource", 3 | "version": "2.0.0", 4 | "description": "load a React Native ImageSource for react-native-webgl & webgltexture-loader", 5 | "main": "lib/ImageSourceTextureLoader.js", 6 | "files": [ 7 | "src", 8 | "lib" 9 | ], 10 | "repository": "https://github.com/gre/webgltexture-loader", 11 | "author": "Gaëtan Renaudeau ", 12 | "license": "MIT", 13 | "dependencies": { 14 | "webgltexture-loader": "^2.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-react-native-imagesource/src/ImageSourceTextureLoader.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import { 3 | globalRegistry, 4 | WebGLTextureLoaderAsyncHashCache 5 | } from "webgltexture-loader"; 6 | 7 | type ImageSource = Object | number; 8 | 9 | class ImageSourceTextureLoader extends WebGLTextureLoaderAsyncHashCache< 10 | ImageSource 11 | > { 12 | rngl = this.gl.getExtension("RN"); 13 | 14 | canLoad(input: any) { 15 | return ( 16 | typeof input === "number" || 17 | (input && typeof input === "object" && typeof input.uri === "string") 18 | ); 19 | } 20 | 21 | disposeTexture(texture: WebGLTexture) { 22 | this.rngl.unloadTexture(texture); 23 | } 24 | 25 | inputHash(input: ImageSource) { 26 | if (typeof input === "number") return input; 27 | return input.uri; 28 | } 29 | 30 | loadNoCache(image: ImageSource) { 31 | const promise = this.rngl.loadTexture({ yflip: true, image }); 32 | const dispose = () => { 33 | // FIXME not sure what we can do for now 34 | }; 35 | return { promise, dispose }; 36 | } 37 | } 38 | 39 | globalRegistry.add(ImageSourceTextureLoader); 40 | 41 | export default ImageSourceTextureLoader; 42 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-react-native/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | 7 | [options] 8 | 9 | [lints] 10 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-react-native/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webgltexture-loader-react-native", 3 | "version": "2.0.0", 4 | "description": "collection of webgltexture-loader in react-native-webgl implementation context", 5 | "main": "lib/index.js", 6 | "files": [ 7 | "src", 8 | "lib" 9 | ], 10 | "repository": "https://github.com/gre/webgltexture-loader", 11 | "author": "Gaëtan Renaudeau ", 12 | "license": "MIT", 13 | "dependencies": { 14 | "webgltexture-loader-react-native-config": "^2.0.0", 15 | "webgltexture-loader-react-native-imagesource": "^2.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/webgltexture-loader-react-native/src/index.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import ConfigTextureLoader from "webgltexture-loader-react-native-config"; 3 | import ImageSourceTextureLoader from "webgltexture-loader-react-native-imagesource"; 4 | 5 | export { ConfigTextureLoader, ImageSourceTextureLoader }; 6 | -------------------------------------------------------------------------------- /packages/webgltexture-loader/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | 7 | [options] 8 | 9 | [lints] 10 | -------------------------------------------------------------------------------- /packages/webgltexture-loader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webgltexture-loader", 3 | "version": "2.0.0", 4 | "description": "load & cache various kind of WebGLTexture with an extensible and loosely coupled system", 5 | "keywords": [ 6 | "webgl", 7 | "gl", 8 | "webgltexture", 9 | "loader" 10 | ], 11 | "main": "lib/index.js", 12 | "files": [ 13 | "src", 14 | "lib" 15 | ], 16 | "repository": "https://github.com/gre/webgltexture-loader", 17 | "author": "Gaëtan Renaudeau ", 18 | "license": "MIT" 19 | } 20 | -------------------------------------------------------------------------------- /packages/webgltexture-loader/src/LoaderResolver.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import type LoadersRegistry from "./LoadersRegistry"; 3 | import type WebGLTextureLoader from "./WebGLTextureLoader"; 4 | import globalRegistry from "./globalRegistry"; 5 | 6 | export default class LoaderResolver { 7 | loaders: Array>; 8 | 9 | constructor( 10 | gl: WebGLRenderingContext, 11 | registry: LoadersRegistry = globalRegistry 12 | ) { 13 | this.loaders = registry.get().map(L => new L(gl)); 14 | } 15 | 16 | dispose() { 17 | this.loaders.forEach(l => l.dispose()); 18 | } 19 | 20 | resolve(input: T): ?WebGLTextureLoader { 21 | return this.loaders.find(loader => loader.canLoad(input)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/webgltexture-loader/src/LoaderResolver.test.js: -------------------------------------------------------------------------------- 1 | import LoaderResolver from "./LoaderResolver"; 2 | import LoadersRegistry from "./LoadersRegistry"; 3 | import WebGLTextureLoaderSyncHashCache from "./WebGLTextureLoaderSyncHashCache"; 4 | 5 | test("an empty LoaderResolver resolves nothing", () => { 6 | const gl = {}; 7 | const resolver = new LoaderResolver(gl); 8 | expect(resolver.resolve(null)).toBeUndefined(); 9 | expect(resolver.resolve(42)).toBeUndefined(); 10 | expect(resolver.resolve("foo")).toBeUndefined(); 11 | resolver.dispose(); 12 | }); 13 | 14 | test("LoaderResolver works with one loader", () => { 15 | const gl = { 16 | deleteTexture: () => {} 17 | }; 18 | const registry = new LoadersRegistry(); 19 | class FakeLoader extends WebGLTextureLoaderSyncHashCache { 20 | canLoad(input) { 21 | return typeof input === "number"; 22 | } 23 | inputHash(input) { 24 | return input; 25 | } 26 | getNoCache(input) { 27 | return { texture: { id: input }, width: 2, height: 2 }; 28 | } 29 | } 30 | registry.add(FakeLoader); 31 | const resolver = new LoaderResolver(gl, registry); 32 | expect(resolver.resolve(null)).toBeUndefined(); 33 | expect(resolver.resolve("foo")).toBeUndefined(); 34 | const loader = resolver.resolve(42); 35 | expect(loader).toBeDefined(); 36 | expect(loader).toBeInstanceOf(FakeLoader); 37 | resolver.dispose(); 38 | }); 39 | -------------------------------------------------------------------------------- /packages/webgltexture-loader/src/LoadersRegistry.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import type WebGLTextureLoader from "./WebGLTextureLoader"; 3 | 4 | /** 5 | * LoadersRegistry 6 | * loaders can define a static priority number. more high is priority, more important the loader is to be used first. 7 | */ 8 | export default class LoadersRegistry { 9 | _loaders: Array>> = []; 10 | 11 | /** 12 | * Add a TextureLoader class to extend texture format support. 13 | */ 14 | add(loader: Class>) { 15 | this._loaders.push(loader); 16 | this._loaders.sort( 17 | (a, b) => 18 | // $FlowFixMe 19 | (typeof b.priority === "number" ? b.priority : 0) - 20 | // $FlowFixMe 21 | (typeof a.priority === "number" ? a.priority : 0) 22 | ); 23 | } 24 | 25 | /** 26 | * Remove a previously added WebGLTextureLoader class. 27 | */ 28 | remove(loader: Class>) { 29 | const i = this._loaders.indexOf(loader); 30 | if (i !== -1) { 31 | this._loaders.splice(i, 1); 32 | } 33 | } 34 | 35 | /** 36 | * List the loaders ordered by most priority first 37 | */ 38 | get() { 39 | return this._loaders; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/webgltexture-loader/src/WebGLTextureLoader.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | 3 | export type TextureAndSize = { 4 | texture: WebGLTexture, 5 | width: number, 6 | height: number 7 | }; 8 | 9 | /** 10 | * a WebGLTextureLoader handle the loading of WebGLTexture for a given input object. 11 | */ 12 | export default class WebGLTextureLoader { 13 | /** 14 | * @property {WebGLRenderingContext} gl - the contextual rendering context 15 | */ 16 | gl: WebGLRenderingContext; 17 | 18 | /** 19 | * 20 | */ 21 | constructor(gl: WebGLRenderingContext) { 22 | this.gl = gl; 23 | } 24 | 25 | /** 26 | * Cancel and clear everything 27 | */ 28 | dispose() {} 29 | 30 | /** 31 | * Check if the loader can handle a given input 32 | */ 33 | canLoad(input: any): boolean { 34 | return false; 35 | } 36 | 37 | /** 38 | * Load the resource by its input. returns a promise of {texture,width,height}. 39 | * idempotent: If load() is called twice with the same input, same promise is returned. 40 | */ 41 | load(input: T): Promise { 42 | return Promise.reject("load() is not implemented"); 43 | } 44 | 45 | /** 46 | * try to get in sync the texture for a given input. otherwise null/undefined. 47 | * If null is returned, load() can be called in order to load the resource that will then be available in a future get() call. 48 | */ 49 | get(input: T): ?TextureAndSize { 50 | return null; 51 | } 52 | 53 | /** 54 | * sync the webgl texture with a loaded input. for instance for