Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"semi": true,
"singleQuote": true,
"trailingComma": "es5"
}
18 changes: 13 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# glslify-import #
# glslify-import

A transform stream for [glslify](http://github.com/stackgl/glslify)
that adds an `import` directive to your shaders.

## Usage ##
## Usage

Given a basic shader:

``` glsl
```glsl
// main.frag
#pragma glslify: import('./common.glsl')

Expand All @@ -18,14 +18,14 @@ void main() {

You can import `./common.glsl`:

``` glsl
```glsl
// common.glsl
varying vec3 color;
```

And have the contents inlined into your shader:

``` glsl
```glsl
varying vec3 color;

void main() {
Expand All @@ -36,3 +36,11 @@ void main() {
You can also use glslify pragmas and the like from your imported files as well.
Useful for the cases when you want to include a common "base" set of
definitions in your shaders without losing the niceties of glslify.

#### Importing chunks

To import a specific chunk from a file you can pass a regular expression with a named capture group called `chunk`.

```glsl
#pragma glslify: import('./common.glsl')(/vec4 diffuseColor([^;]+);(?<chunk>.*)}/gs)
```
175 changes: 114 additions & 61 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,93 +1,146 @@
const string = require('glsl-token-string')
const tokenize = require('glsl-tokenizer')
const resolve = require('glsl-resolve')
const path = require('path')
const fs = require('fs')
const string = require('glsl-token-string');
const tokenize = require('glsl-tokenizer');
const resolve = require('glsl-resolve');
const path = require('path');
const fs = require('fs');

module.exports = glslifyImport
module.exports = glslifyImport;
module.exports.sync = glslifyImport;

function glslifyImport (file, src, opts, done) {
const tokens = tokenize(src)
function glslifyImport(file, src, opts, done) {
const tokens = tokenize(src);

var total = 0
var total = 0;

for (var i = 0; i < tokens.length; i++) (function (i) {
var token = tokens[i]
if (token.type !== 'preprocessor') return
for (var i = 0; i < tokens.length; i++)
(function (i) {
var token = tokens[i];
if (token.type !== 'preprocessor') return;

var imported = /#pragma glslify:\s*import\(([^\)]+)\)/.exec(token.data)
if (!imported) return
if (!imported[1]) return
var imported = /#pragma glslify:\s*import(.+)/.exec(token.data);

var target = imported[1]
.trim()
.replace(/^'|'$/g, '')
.replace(/^"|"$/g, '')
if (!imported) return;

total++
imported = imported[0].match(
/\((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))+\)/g
);

var basedir = path.dirname(file)
if (!imported[0]) return;

if (typeof done === 'function') {
resolve(target, { basedir: basedir }, function (err, resolved) {
if (err) return done(err)
imported = imported.map(function (str) {
return str
.trim()
.replace(/^\(|\)$/g, '')
.replace(/^'|'$/g, '')
.replace(/^"|"$/g, '');
});

fs.readFile(resolved, 'utf8', function (err, contents) {
if (err) return done(err)
var target = imported[0];

contents = modifyRequirePaths(contents, basedir, target)
var chunkPattern;
var chunkFlags;

glslifyImport(resolved, contents, opts, function (err, contents) {
if (err) return done(err)
if (imported[1]) {
var chunkParts = imported[1].split('/');
chunkPattern = chunkParts[1];
chunkFlags = chunkParts.slice(-1);
}

token.data = contents
if (--total) return
total++;

done(null, string(tokens))
})
})
})
} else {
var resolved = resolve.sync(target, { basedir: basedir });
var contents = fs.readFileSync(resolved, 'utf8');
contents = modifyRequirePaths(contents, basedir, target);
token.data = glslifyImport(resolved, contents, opts);
total--;
}
})(i)
var basedir = path.dirname(file);

if (typeof done === 'function') {
resolve(target, { basedir: basedir }, function (err, resolved) {
if (err) return done(err);

fs.readFile(resolved, 'utf8', function (err, contents) {
if (err) return done(err);

contents = extractChunk(contents, chunkPattern, chunkFlags);
contents = modifyRequirePaths(contents, basedir, target);

glslifyImport(resolved, contents, opts, function (err, contents) {
if (err) return done(err);

token.data = contents;
if (--total) return;

done(null, string(tokens));
});
});
});
} else {
var resolved = resolve.sync(target, { basedir: basedir });
var contents = fs.readFileSync(resolved, 'utf8');

if (!total) return typeof done === 'function' ? done(null, src) : string(tokens);
contents = extractChunk(contents, chunkPattern, chunkFlags);
contents = modifyRequirePaths(contents, basedir, target);

token.data = glslifyImport(resolved, contents, opts);

total--;
}
})(i);

if (!total)
return typeof done === 'function' ? done(null, src) : string(tokens);
}

function modifyRequirePaths (src, basedir, baseTarget) {
const tokens = tokenize(src)
function extractChunk(contents, chunkPattern, chunkFlags) {
if (chunkPattern) {
var chunkContents = new RegExp(chunkPattern, chunkFlags).exec(contents);

var targetDir = path.dirname(path.resolve(basedir, baseTarget))
if (chunkContents && chunkContents[1]) {
contents =
chunkContents.groups && chunkContents.groups.chunk
? chunkContents.groups.chunk
: chunkContents[1];
}
}

for (var i = 0; i < tokens.length; i++) {
var token = tokens[i]
if (token.type !== 'preprocessor') continue
return contents;
}

var required = /#pragma glslify:\s*([^=\s]+)\s*=\s*require\(([^\)]+)\)/.exec(token.data)
if (!required) continue
if (!required[2]) continue
function modifyRequirePaths(src, basedir, baseTarget) {
const tokens = tokenize(src);

var name = required[1]
var maps = required[2].split(/\s?,\s?/g)
var target = maps.shift()
var targetDir = path.dirname(path.resolve(basedir, baseTarget));

for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
if (token.type !== 'preprocessor') continue;

var required = /#pragma glslify:\s*([^=\s]+)\s*=\s*require\(([^\)]+)\)/.exec(
token.data
);
if (!required) continue;
if (!required[2]) continue;

var name = required[1];
var maps = required[2].split(/\s?,\s?/g);
var target = maps
.shift()
.trim()
.replace(/^'|'$/g, '')
.replace(/^"|"$/g, '')
.replace(/^"|"$/g, '');

var resolvedTarget = path.resolve(targetDir, target)
var resolvedTarget = path.resolve(targetDir, target);

if (name) {
token.data = '#pragma glslify: ' + name + ' = require("' + [resolvedTarget].concat(maps).join(', ') + '")'
token.data =
'#pragma glslify: ' +
name +
' = require("' +
[resolvedTarget].concat(maps).join(', ') +
'")';
} else {
token.data = '#pragma glslify: require("' + [resolvedTarget].concat(maps).join(', ') + '")'
token.data =
'#pragma glslify: require("' +
[resolvedTarget].concat(maps).join(', ') +
'")';
}
}

return string(tokens)
return string(tokens);
}
Loading