mirror of
https://github.com/SamEyeBam/animate.git
synced 2025-12-15 18:21:05 +00:00
larry babby and threejs for glsl
This commit is contained in:
156
webGl/my-threejs-test/node_modules/glslify-deps/README.md
generated
vendored
Normal file
156
webGl/my-threejs-test/node_modules/glslify-deps/README.md
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
# glslify-deps
|
||||
|
||||
Walk the dependency graph of a [glslify](http://github.com/stackgl/glslify)
|
||||
shader.
|
||||
|
||||
`glslify-deps` is responsible for resolving your shader's dependencies and
|
||||
applying their transforms before the actual source modification occurs. You may
|
||||
notice some parallels here with [browserify](http://browserify.org)'s
|
||||
[module-deps](http://github.com/substack/module-deps) package.
|
||||
|
||||
While `glslify-deps` is an "internal" package for `glslify`, it may be useful
|
||||
to use this package directly in specific cases, e.g. building a file tree
|
||||
server-side but bundling the final shader on the client.
|
||||
|
||||
## Module API
|
||||
|
||||
There is an asynchronous and a synchronous API:
|
||||
|
||||
``` js
|
||||
var glslifyDeps = require('glslify-deps')
|
||||
var glslifyDepsSync = require('glslify-deps/sync')
|
||||
```
|
||||
|
||||
The asynchronous API is documented below. For every method in the asychronous
|
||||
API, instead of a `callback(err, result)`, the result is available as the return
|
||||
value of the method.
|
||||
|
||||
### `depper = glslifyDeps([options])`
|
||||
|
||||
Creates a fresh `glslify-deps` instance. Accepts the following options:
|
||||
|
||||
* `cwd`: the current working directory to resolve relative file paths from.
|
||||
* `readFile`: pass in a custom function reading files.
|
||||
* `resolve`: pass in a custom function for resolving require calls. It has
|
||||
the same signature as [glsl-resolve](http://github.com/hughsk/glsl-resolve).
|
||||
* `files`: a filename/source object mapping of files to prepopulate
|
||||
the file cache with. Useful for overriding particular file paths manually,
|
||||
most notably the "entry" file.
|
||||
|
||||
### `depper.transform(transform, [options])`
|
||||
|
||||
Adds a new transform – should be used before calling `depper.add`.
|
||||
|
||||
`transform` may either be a string (which is resolved like a `require` call),
|
||||
or a function. More information on transforms can be found below.
|
||||
|
||||
### `depper.add(filename, [callback])`
|
||||
|
||||
Adds a new file to the dependency graph.
|
||||
|
||||
### `depper.inline(source, basedir, [callback])`
|
||||
|
||||
Adds a new inline file to the dependency graph, where `source` is the GLSL
|
||||
source to include and `basedir` is the directory to pretend it's being
|
||||
created in. A `basedir` is required to properly resolve requires and transforms,
|
||||
and defaults to `process.cwd()`.
|
||||
|
||||
### `depper.on('file', cb(filename))`
|
||||
|
||||
Emitted whenever a new file has been included in the dependency graph.
|
||||
|
||||
## Example Output
|
||||
|
||||
``` json
|
||||
[
|
||||
{
|
||||
"id": 0,
|
||||
"deps": { "glsl-random": 1 },
|
||||
"file": "index.glsl",
|
||||
"source": "precision mediump float;\n#pragma glslify: random = require(glsl-random)\n",
|
||||
"entry": true
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"deps": {},
|
||||
"file": "node_modules/glsl-random/index.glsl",
|
||||
"source": "highp float random(vec2 co)\n{\n highp float a = 12.9898;\n highp float b = 78.233;\n highp float c = 43758.5453;\n highp float dt= dot(co.xy ,vec2(a,b));\n highp float sn= mod(dt,3.14);\n return fract(sin(sn) * c);\n}\n\n#pragma glslify: export(random)",
|
||||
"entry": false
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Transform API
|
||||
|
||||
The transform API has changed since glslify 1.0 to make it more "vanilla".
|
||||
|
||||
With the asynchronous API, transforms have this signature:
|
||||
|
||||
``` javascript
|
||||
module.exports = function(file, source, options, done) {
|
||||
done(null, source.toUpperCase())
|
||||
}
|
||||
```
|
||||
|
||||
and using the synchronous API, transforms have this signature:
|
||||
|
||||
``` javascript
|
||||
module.exports.sync = function(file, source, options) {
|
||||
return source.toUpperCase()
|
||||
}
|
||||
```
|
||||
|
||||
For an example that is compatible with both the async and sync APIs, here's
|
||||
[glslify-hex](http://github.com/hughsk/glslify-hex)
|
||||
rewritten using the new API:
|
||||
|
||||
``` javascript
|
||||
var through = require('through')
|
||||
|
||||
var regexLong = /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?/gi
|
||||
var regexShort = /#([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?/gi
|
||||
|
||||
module.exports = transform
|
||||
module.exports.sync = transform
|
||||
|
||||
function transform(filename, src, opts, done) {
|
||||
src = src.replace(regexShort, function(whole, r, g, b, a) {
|
||||
return !a
|
||||
? '#' + r + r + g + g + b + b
|
||||
: '#' + r + r + g + g + b + b + a + a
|
||||
}).replace(regexLong, function(whole, r, g, b, a) {
|
||||
r = makeFloat(parseInt(r, 16) / 255)
|
||||
g = makeFloat(parseInt(g, 16) / 255)
|
||||
b = makeFloat(parseInt(b, 16) / 255)
|
||||
a = makeFloat(parseInt(a, 16) / 255)
|
||||
|
||||
return isNaN(a)
|
||||
? 'vec3('+[r,g,b].join(',')+')'
|
||||
: 'vec4('+[r,g,b,a].join(',')+')'
|
||||
})
|
||||
|
||||
if (typeof done === 'function') done(null, src)
|
||||
return src
|
||||
}
|
||||
|
||||
function makeFloat(n) {
|
||||
return String(n).indexOf('.') === -1
|
||||
? n + '.'
|
||||
: n
|
||||
}
|
||||
```
|
||||
|
||||
## Transforms in `package.json`
|
||||
|
||||
Transforms now support options specified in `package.json`:
|
||||
|
||||
``` json
|
||||
{
|
||||
"glslify": {
|
||||
"transform": [
|
||||
"glslify-hex",
|
||||
["glslify-optimize", { "mangle": true }]
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
362
webGl/my-threejs-test/node_modules/glslify-deps/index.js
generated
vendored
Normal file
362
webGl/my-threejs-test/node_modules/glslify-deps/index.js
generated
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
var tokenize = require('glsl-tokenizer/string')
|
||||
var findup = require('@choojs/findup')
|
||||
var fs = require('graceful-fs')
|
||||
var map = require('map-limit')
|
||||
var inherits = require('inherits')
|
||||
var Emitter = require('events/')
|
||||
var path = require('path')
|
||||
|
||||
var glslResolve = require('glsl-resolve')
|
||||
var nodeResolve = require('resolve')
|
||||
|
||||
var inlineName = '__INLINE__' + Math.random()
|
||||
var inlineSource = ''
|
||||
|
||||
module.exports = Depper
|
||||
|
||||
/**
|
||||
* Creates a new instance of glslify-deps. Generally, you'll
|
||||
* want to use one instance per bundle.
|
||||
*
|
||||
* @class
|
||||
* @param {String} cwd The root directory of your shader. Defaults to process.cwd()
|
||||
*/
|
||||
inherits(Depper, Emitter)
|
||||
function Depper(opts) {
|
||||
if (!(this instanceof Depper)) return new Depper(opts)
|
||||
Emitter.call(this)
|
||||
|
||||
opts = typeof opts === 'string' ? { cwd: opts } : opts
|
||||
opts = opts || {}
|
||||
|
||||
this._deps = []
|
||||
this._cwd = opts.cwd || process.cwd()
|
||||
this._cache = {}
|
||||
this._i = 0
|
||||
this._transforms = []
|
||||
this._trCache = {}
|
||||
this._fileCache = opts.files || {}
|
||||
|
||||
this._globalTransforms = []
|
||||
|
||||
this._readFile = cacheWrap(opts.readFile || defaultRead, this._fileCache)
|
||||
this.resolve = opts.resolve || glslResolve
|
||||
|
||||
if (typeof this._cwd !== 'string') {
|
||||
throw new Error('glslify-deps: cwd must be a string path')
|
||||
}
|
||||
}
|
||||
|
||||
Depper.prototype.inline = function(source, basedir, done) {
|
||||
var inlineFile = path.resolve(basedir || process.cwd(), inlineName)
|
||||
|
||||
inlineSource = source
|
||||
|
||||
this.add(inlineFile, function(err, tree) {
|
||||
done && done(err, !err && tree)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a transform to use on your local dependencies.
|
||||
* Note that this should be used before calling `add`.
|
||||
*
|
||||
* Transforms are handled using a different API to browserify, e.g.:
|
||||
*
|
||||
* ``` js
|
||||
* module.exports = function transform(filename, src, opts, done) {
|
||||
* done(null, src.toUpperCase())
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Where `filename` is the absolute file path, `src` is the shader source
|
||||
* as a string, `opts` is an options object for configuration, and `done`
|
||||
* is a callback which takes the transformed shader source.
|
||||
*
|
||||
* @param {String|Function} transform
|
||||
* @param {Object} opts
|
||||
*/
|
||||
Depper.prototype.transform = function(transform, opts) {
|
||||
var name = typeof transform === 'string' ? transform : null
|
||||
var list = opts && opts.global
|
||||
? this._globalTransforms
|
||||
: this._transforms
|
||||
|
||||
// post transforms are ignored by glslify-deps, to be handled
|
||||
// by glslify after the file has been bundled.
|
||||
if (opts && opts.post) return this
|
||||
|
||||
transform = this.resolveTransform(transform)
|
||||
list.push({ tr: transform, opts: opts, name: name })
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a shader file to the graph, including its dependencies
|
||||
* which are resolved in this step. Transforms are also applied
|
||||
* in the process too, as they may potentially add or remove dependent
|
||||
* modules.
|
||||
*
|
||||
* @param {String} filename The absolute path of this file.
|
||||
* @param {String} src The shader source for this file.
|
||||
* @param {Function} done(err, deps)
|
||||
*
|
||||
* The `done` callback will be called when the entire graph has been
|
||||
* resolved, and will include an array of dependencies discovered
|
||||
* so far as its second argument.
|
||||
*/
|
||||
Depper.prototype.add = function(filename, done) {
|
||||
var basedir = path.dirname(filename = path.resolve(filename))
|
||||
var cache = this._cache
|
||||
var self = this
|
||||
var exports = []
|
||||
var imports = []
|
||||
|
||||
var dep = {
|
||||
id: this._i++
|
||||
, deps: {}
|
||||
, file: filename
|
||||
, source: null
|
||||
, entry: this._i === 1
|
||||
}
|
||||
|
||||
this._deps.push(dep)
|
||||
this.readFile(filename, function(err, src) {
|
||||
if (err) return done(err)
|
||||
|
||||
self.getTransformsForFile(filename, function(err, trs) {
|
||||
if (err) return done(err)
|
||||
|
||||
self.emit('file', filename)
|
||||
self.applyTransforms(filename, src, trs, function(err, src) {
|
||||
if (err) return done(err)
|
||||
|
||||
dep.source = src
|
||||
extractPreprocessors()
|
||||
resolveImports(function(err) {
|
||||
setTimeout(function() {
|
||||
done && done(err, !err && self._deps)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
return dep
|
||||
|
||||
function extractPreprocessors() {
|
||||
var tokens = tokenize(dep.source)
|
||||
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
var token = tokens[i]
|
||||
if (token.type !== 'preprocessor') continue
|
||||
|
||||
var data = token.data
|
||||
if (!glslifyPreprocessor(data)) continue
|
||||
|
||||
var exp = glslifyExport(data)
|
||||
var imp = glslifyImport(data)
|
||||
if (exp) exports.push(exp[1])
|
||||
if (imp) imports.push(imp[2])
|
||||
}
|
||||
}
|
||||
|
||||
function resolveImports(resolved) {
|
||||
map(imports, 10, function(imp, next) {
|
||||
var importName = imp.split(/\s*,\s*/).shift()
|
||||
|
||||
importName = importName.trim()
|
||||
importName = importName.replace(/^'|'$/g, '')
|
||||
importName = importName.replace(/^"|"$/g, '')
|
||||
|
||||
self.resolve(importName, { basedir: basedir }, function(err, resolved) {
|
||||
if (err) return next(err)
|
||||
|
||||
if (cache[resolved]) {
|
||||
dep.deps[importName] = cache[resolved].id
|
||||
return next()
|
||||
}
|
||||
|
||||
cache[resolved] = self.add(resolved, function(err) {
|
||||
if (err) return next(err)
|
||||
dep.deps[importName] = cache[resolved].id
|
||||
next()
|
||||
})
|
||||
})
|
||||
}, resolved)
|
||||
}
|
||||
}
|
||||
|
||||
Depper.prototype.readFile = function(filename, done) {
|
||||
if (path.basename(filename) !== inlineName)
|
||||
return this._readFile(filename, done)
|
||||
|
||||
return done(null, inlineSource)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which transforms to use for a particular file.
|
||||
* The rules here are the same you see in browserify:
|
||||
*
|
||||
* - your shader files will have your specified transforms applied to them
|
||||
* - shader files in node_modules do not get local transforms
|
||||
* - all files will apply transforms specified in `glslify.transform` in your
|
||||
* `package.json` file, albeit after any transforms you specified using
|
||||
* `depper.transform`.
|
||||
*
|
||||
* @param {String} filename The absolute path of the file in question.
|
||||
*/
|
||||
Depper.prototype.getTransformsForFile = function(filename, done) {
|
||||
var self = this
|
||||
var entry = this._deps[0]
|
||||
|
||||
if (!entry) return done(new Error(
|
||||
'getTransformsForFile may only be called after adding your entry file'
|
||||
))
|
||||
|
||||
var entryDir = path.dirname(path.resolve(entry.file))
|
||||
var fileDir = path.dirname(path.resolve(filename))
|
||||
var relative = path.relative(entryDir, fileDir).split(path.sep)
|
||||
var node_modules = relative.indexOf('node_modules') !== -1
|
||||
var trLocal = node_modules ? [] : this._transforms
|
||||
var trCache = this._trCache
|
||||
|
||||
if (trCache[fileDir]) {
|
||||
return done(null, trCache[fileDir])
|
||||
}
|
||||
|
||||
findup(fileDir, 'package.json', function(err, found) {
|
||||
var notFound = err && err.message === 'not found'
|
||||
if (notFound) return register([])
|
||||
if (err) return done(err)
|
||||
|
||||
var pkg = path.join(found, 'package.json')
|
||||
|
||||
self.readFile(pkg, function(err, pkgjson) {
|
||||
if (err) return done(err)
|
||||
|
||||
try {
|
||||
pkgjson = JSON.parse(pkgjson)
|
||||
} catch(e) { return done(e) }
|
||||
|
||||
var transforms = (
|
||||
pkgjson['glslify']
|
||||
&& pkgjson['glslify']['transform']
|
||||
|| []
|
||||
)
|
||||
|
||||
transforms = transforms.map(function(key) {
|
||||
var transform = Array.isArray(key)
|
||||
? key
|
||||
: [key, {}]
|
||||
|
||||
var key = transform[0]
|
||||
var opt = transform[1]
|
||||
|
||||
if (opt) {
|
||||
delete opt.global
|
||||
delete opt.post
|
||||
}
|
||||
|
||||
return { tr: key, opts: opt, name: key }
|
||||
}).map(function(tr) {
|
||||
tr.tr = self.resolveTransform(tr.tr)
|
||||
return tr
|
||||
})
|
||||
|
||||
register(transforms)
|
||||
})
|
||||
})
|
||||
|
||||
function register(transforms) {
|
||||
done(null, trCache[fileDir] = trLocal
|
||||
.concat(transforms)
|
||||
.concat(self._globalTransforms))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a transform.
|
||||
*
|
||||
* Functions are retained as-is.
|
||||
* Strings are resolved using node's `require` resolution algorithm,
|
||||
* and then required directly.
|
||||
*
|
||||
* @param {String|Function} transform
|
||||
*/
|
||||
Depper.prototype.resolveTransform = function(transform) {
|
||||
if (typeof transform === 'string') {
|
||||
transform = nodeResolve.sync(transform, {
|
||||
basedir: this._cwd
|
||||
})
|
||||
|
||||
transform = require(transform)
|
||||
}
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a transform to a string.
|
||||
*
|
||||
* Note that transforms here are passed in differently to other methods:
|
||||
* - `tr.tr` should point to the transform function.
|
||||
* - `tr.opts` should contain the options for the transform, if applicable.
|
||||
*
|
||||
* @param {String} filename The absolute path of the file you're transforming.
|
||||
* @param {String} src The shader source you'd like to transform.
|
||||
* @param {Array} transforms The transforms you'd like to apply.
|
||||
* @param {Function} done(err, transformed)
|
||||
*/
|
||||
Depper.prototype.applyTransforms = function(filename, src, transforms, done) {
|
||||
var i = 0
|
||||
|
||||
next(null, src)
|
||||
function next(err, updated) {
|
||||
if (err) return done(err)
|
||||
if (i >= transforms.length) return done(null, updated)
|
||||
|
||||
var tr = transforms[i++]
|
||||
var opts = tr.opts
|
||||
|
||||
if (!opts || typeof opts !== 'object') opts = {}
|
||||
tr.tr(filename, updated+'', tr.opts, next)
|
||||
}
|
||||
}
|
||||
|
||||
function glslifyPreprocessor(data) {
|
||||
return /#pragma glslify:/.test(data)
|
||||
}
|
||||
|
||||
function glslifyExport(data) {
|
||||
return /#pragma glslify:\s*export\(([^\)]+)\)/.exec(data)
|
||||
}
|
||||
|
||||
function glslifyImport(data) {
|
||||
return /#pragma glslify:\s*([^=\s]+)\s*=\s*require\(([^\)]+)\)/.exec(data)
|
||||
}
|
||||
|
||||
function defaultRead(src, done) {
|
||||
fs.readFile(src, 'utf8', done)
|
||||
}
|
||||
|
||||
function cacheWrap(read, cache) {
|
||||
// resolve all cached files such that they match
|
||||
// all of the paths glslify handles, which are otherwise
|
||||
// absolute
|
||||
cache = Object.keys(cache).reduce(function(newCache, file) {
|
||||
newCache[path.resolve(file)] = cache[file]
|
||||
return newCache
|
||||
}, {})
|
||||
|
||||
return function readFromCache(filename, done) {
|
||||
if (!cache[filename]) {
|
||||
return read(filename, done)
|
||||
}
|
||||
|
||||
process.nextTick(function() {
|
||||
done(null, cache[filename])
|
||||
})
|
||||
}
|
||||
}
|
||||
40
webGl/my-threejs-test/node_modules/glslify-deps/package.json
generated
vendored
Normal file
40
webGl/my-threejs-test/node_modules/glslify-deps/package.json
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "glslify-deps",
|
||||
"version": "1.3.2",
|
||||
"scripts": {
|
||||
"test": "node test | tap-spec",
|
||||
"coverage": "istanbul cover test/index.js && http-server coverage/lcov-report/glslify-deps"
|
||||
},
|
||||
"dependencies": {
|
||||
"@choojs/findup": "^0.2.0",
|
||||
"events": "^3.2.0",
|
||||
"glsl-resolve": "0.0.1",
|
||||
"glsl-tokenizer": "^2.0.0",
|
||||
"graceful-fs": "^4.1.2",
|
||||
"inherits": "^2.0.1",
|
||||
"map-limit": "0.0.1",
|
||||
"resolve": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"glsl-random": "0.0.4",
|
||||
"glslify-hex": "^2.0.0",
|
||||
"istanbul": "^0.3.5",
|
||||
"tap-spec": "^4.1.1",
|
||||
"tape": "^3.0.2"
|
||||
},
|
||||
"description": "Walk the dependency graph of a glslify shader.",
|
||||
"main": "index.js",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/stackgl/glslify-deps.git"
|
||||
},
|
||||
"author": "Hugh Kennedy <hughskennedy@gmail.com> (http://hughsk.io/)",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/stackgl/glslify-deps/issues"
|
||||
},
|
||||
"homepage": "https://github.com/stackgl/glslify-deps#readme"
|
||||
}
|
||||
327
webGl/my-threejs-test/node_modules/glslify-deps/sync.js
generated
vendored
Normal file
327
webGl/my-threejs-test/node_modules/glslify-deps/sync.js
generated
vendored
Normal file
@@ -0,0 +1,327 @@
|
||||
var tokenize = require('glsl-tokenizer/string')
|
||||
var findup = require('@choojs/findup').sync
|
||||
var fs = require('graceful-fs')
|
||||
var map = require('map-limit')
|
||||
var inherits = require('inherits')
|
||||
var Emitter = require('events/')
|
||||
var path = require('path')
|
||||
|
||||
var glslResolve = require('glsl-resolve').sync
|
||||
var nodeResolve = require('resolve').sync
|
||||
|
||||
var inlineName = '__INLINE__' + Math.random()
|
||||
var inlineSource = ''
|
||||
|
||||
module.exports = Depper
|
||||
|
||||
/**
|
||||
* Creates a new instance of glslify-deps. Generally, you'll
|
||||
* want to use one instance per bundle.
|
||||
*
|
||||
* @class
|
||||
* @param {String} cwd The root directory of your shader. Defaults to process.cwd()
|
||||
*/
|
||||
inherits(Depper, Emitter)
|
||||
function Depper(opts) {
|
||||
if (!(this instanceof Depper)) return new Depper(opts)
|
||||
Emitter.call(this)
|
||||
|
||||
opts = typeof opts === 'string' ? { cwd: opts } : opts
|
||||
opts = opts || {}
|
||||
|
||||
this._deps = []
|
||||
this._cwd = opts.cwd || process.cwd()
|
||||
this._cache = {}
|
||||
this._i = 0
|
||||
this._transforms = []
|
||||
this._trCache = {}
|
||||
this._fileCache = opts.files || {}
|
||||
|
||||
this._globalTransforms = []
|
||||
|
||||
this._readFile = cacheWrap(opts.readFileSync || defaultRead, this._fileCache)
|
||||
this.resolve = opts.resolve || glslResolve
|
||||
|
||||
if (typeof this._cwd !== 'string') {
|
||||
throw new Error('glslify-deps: cwd must be a string path')
|
||||
}
|
||||
}
|
||||
|
||||
Depper.prototype.inline = function(source, basedir) {
|
||||
var inlineFile = path.resolve(basedir || process.cwd(), inlineName)
|
||||
|
||||
inlineSource = source
|
||||
|
||||
return this.add(inlineFile)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a transform to use on your local dependencies.
|
||||
* Note that this should be used before calling `add`.
|
||||
*
|
||||
* Transforms are handled using a different API to browserify, e.g.:
|
||||
*
|
||||
* ``` js
|
||||
* exports.sync = function transform(filename, src, opts) {
|
||||
* return src.toUpperCase()
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* This is also different from the async transform API.
|
||||
*
|
||||
* Where `filename` is the absolute file path, `src` is the shader source
|
||||
* as a string, `opts` is an options object for configuration.
|
||||
*
|
||||
* @param {String|Function} transform
|
||||
* @param {Object} opts
|
||||
*/
|
||||
Depper.prototype.transform = function(transform, opts) {
|
||||
var name = typeof transform === 'string' ? transform : null
|
||||
var list = opts && opts.global
|
||||
? this._globalTransforms
|
||||
: this._transforms
|
||||
|
||||
// post transforms are ignored by glslify-deps, to be handled
|
||||
// by glslify after the file has been bundled.
|
||||
if (opts && opts.post) return this
|
||||
|
||||
transform = this.resolveTransform(transform)
|
||||
list.push({ tr: transform, opts: opts, name: name })
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a shader file to the graph, including its dependencies
|
||||
* which are resolved in this step. Transforms are also applied
|
||||
* in the process too, as they may potentially add or remove dependent
|
||||
* modules.
|
||||
*
|
||||
* @param {String} filename The absolute path of this file.
|
||||
* @param {String} src The shader source for this file.
|
||||
*
|
||||
* Returns an array of dependencies discovered so far as its second argument.
|
||||
*/
|
||||
Depper.prototype.add = function(filename) {
|
||||
var basedir = path.dirname(filename = path.resolve(filename))
|
||||
var cache = this._cache
|
||||
var self = this
|
||||
var exports = []
|
||||
var imports = []
|
||||
|
||||
var dep = {
|
||||
id: this._i++
|
||||
, deps: {}
|
||||
, file: filename
|
||||
, source: null
|
||||
, entry: this._i === 1
|
||||
}
|
||||
|
||||
this._deps.push(dep)
|
||||
var src = this.readFile(filename)
|
||||
var trs = self.getTransformsForFile(filename)
|
||||
self.emit('file', filename)
|
||||
src = self.applyTransforms(filename, src, trs)
|
||||
dep.source = src
|
||||
extractPreprocessors()
|
||||
|
||||
resolveImports()
|
||||
return self._deps
|
||||
|
||||
function extractPreprocessors() {
|
||||
var tokens = tokenize(dep.source)
|
||||
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
var token = tokens[i]
|
||||
if (token.type !== 'preprocessor') continue
|
||||
|
||||
var data = token.data
|
||||
if (!glslifyPreprocessor(data)) continue
|
||||
|
||||
var exp = glslifyExport(data)
|
||||
var imp = glslifyImport(data)
|
||||
if (exp) exports.push(exp[1])
|
||||
if (imp) imports.push(imp[2])
|
||||
}
|
||||
}
|
||||
|
||||
function resolveImports(resolved) {
|
||||
imports.forEach(function (imp) {
|
||||
var importName = imp.split(/\s*,\s*/).shift()
|
||||
|
||||
importName = importName.trim()
|
||||
importName = importName.replace(/^'|'$/g, '')
|
||||
importName = importName.replace(/^"|"$/g, '')
|
||||
|
||||
var resolved = self.resolve(importName, { basedir: basedir })
|
||||
if (cache[resolved]) {
|
||||
dep.deps[importName] = cache[resolved].id
|
||||
}
|
||||
var i = self._i
|
||||
cache[resolved] = self.add(resolved)[i]
|
||||
dep.deps[importName] = cache[resolved].id
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Depper.prototype.readFile = function(filename) {
|
||||
if (path.basename(filename) !== inlineName)
|
||||
return this._readFile(filename)
|
||||
|
||||
return inlineSource
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which transforms to use for a particular file.
|
||||
* The rules here are the same you see in browserify:
|
||||
*
|
||||
* - your shader files will have your specified transforms applied to them
|
||||
* - shader files in node_modules do not get local transforms
|
||||
* - all files will apply transforms specified in `glslify.transform` in your
|
||||
* `package.json` file, albeit after any transforms you specified using
|
||||
* `depper.transform`.
|
||||
*
|
||||
* @param {String} filename The absolute path of the file in question.
|
||||
*/
|
||||
Depper.prototype.getTransformsForFile = function(filename) {
|
||||
var self = this
|
||||
var entry = this._deps[0]
|
||||
|
||||
if (!entry) throw new Error(
|
||||
'getTransformsForFile may only be called after adding your entry file'
|
||||
)
|
||||
|
||||
var entryDir = path.dirname(path.resolve(entry.file))
|
||||
var fileDir = path.dirname(path.resolve(filename))
|
||||
var relative = path.relative(entryDir, fileDir).split(path.sep)
|
||||
var node_modules = relative.indexOf('node_modules') !== -1
|
||||
var trLocal = node_modules ? [] : this._transforms
|
||||
var trCache = this._trCache
|
||||
|
||||
if (trCache[fileDir]) {
|
||||
return trCache[fileDir]
|
||||
}
|
||||
|
||||
try { var found = findup(fileDir, 'package.json') }
|
||||
catch (err) {
|
||||
var notFound = err.message === 'not found'
|
||||
if (notFound) return register([])
|
||||
else throw err
|
||||
}
|
||||
|
||||
var pkg = path.join(found, 'package.json')
|
||||
var pkgjson = JSON.parse(self.readFile(pkg))
|
||||
|
||||
var transforms = (
|
||||
pkgjson['glslify']
|
||||
&& pkgjson['glslify']['transform']
|
||||
|| []
|
||||
)
|
||||
|
||||
transforms = transforms.map(function(key) {
|
||||
var transform = Array.isArray(key)
|
||||
? key
|
||||
: [key, {}]
|
||||
|
||||
var key = transform[0]
|
||||
var opt = transform[1]
|
||||
|
||||
if (opt) {
|
||||
delete opt.global
|
||||
delete opt.post
|
||||
}
|
||||
|
||||
return { tr: key, opts: opt, name: key }
|
||||
}).map(function(tr) {
|
||||
tr.tr = self.resolveTransform(tr.tr)
|
||||
return tr
|
||||
})
|
||||
|
||||
return register(transforms)
|
||||
|
||||
function register(transforms) {
|
||||
return trCache[fileDir] = trLocal
|
||||
.concat(transforms)
|
||||
.concat(self._globalTransforms)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a transform.
|
||||
*
|
||||
* Functions are retained as-is.
|
||||
* Strings are resolved using node's `require` resolution algorithm,
|
||||
* and then required directly.
|
||||
*
|
||||
* @param {String|Function} transform
|
||||
*/
|
||||
Depper.prototype.resolveTransform = function(transform) {
|
||||
if (typeof transform === 'string') {
|
||||
transform = nodeResolve(transform, {
|
||||
basedir: this._cwd
|
||||
})
|
||||
|
||||
var m = require(transform)
|
||||
if (!m || typeof m.sync !== 'function') {
|
||||
throw new Error('transform ' + transform + ' does not provide a'
|
||||
+ ' synchronous interface')
|
||||
}
|
||||
transform = m.sync
|
||||
}
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a transform to a string.
|
||||
*
|
||||
* Note that transforms here are passed in differently to other methods:
|
||||
* - `tr.tr` should point to the transform function.
|
||||
* - `tr.opts` should contain the options for the transform, if applicable.
|
||||
*
|
||||
* @param {String} filename The absolute path of the file you're transforming.
|
||||
* @param {String} src The shader source you'd like to transform.
|
||||
* @param {Array} transforms The transforms you'd like to apply.
|
||||
*
|
||||
* Returns the transformed source string.
|
||||
*/
|
||||
Depper.prototype.applyTransforms = function(filename, src, transforms) {
|
||||
transforms.forEach(function (tr) {
|
||||
var opts = tr.opts
|
||||
if (!opts || typeof opts !== 'object') opts = {}
|
||||
src = tr.tr(filename, src+'', tr.opts)
|
||||
})
|
||||
return src
|
||||
}
|
||||
|
||||
function glslifyPreprocessor(data) {
|
||||
return /#pragma glslify:/.test(data)
|
||||
}
|
||||
|
||||
function glslifyExport(data) {
|
||||
return /#pragma glslify:\s*export\(([^\)]+)\)/.exec(data)
|
||||
}
|
||||
|
||||
function glslifyImport(data) {
|
||||
return /#pragma glslify:\s*([^=\s]+)\s*=\s*require\(([^\)]+)\)/.exec(data)
|
||||
}
|
||||
|
||||
function defaultRead(src) {
|
||||
return fs.readFileSync(src, 'utf8')
|
||||
}
|
||||
|
||||
function cacheWrap(read, cache) {
|
||||
// resolve all cached files such that they match
|
||||
// all of the paths glslify handles, which are otherwise
|
||||
// absolute
|
||||
cache = Object.keys(cache).reduce(function(newCache, file) {
|
||||
newCache[path.resolve(file)] = cache[file]
|
||||
return newCache
|
||||
}, {})
|
||||
|
||||
return function readFromCache(filename) {
|
||||
if (!cache[filename]) {
|
||||
cache[filename] = read(filename)
|
||||
}
|
||||
return cache[filename]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user