@awayjs/stage
Version:
Stage for AwayJS
288 lines (287 loc) • 12.4 kB
JavaScript
import { Mapping } from './Mapping';
import { Settings } from '../Settings';
var AGLSLParser = /** @class */ (function () {
function AGLSLParser() {
this._usedLibs = {};
this._usedTemps = {};
}
AGLSLParser.prototype._linkLib = function (opcode) {
var libs = this._usedLibs;
if (!libs[opcode] && Mapping.lib[opcode]) {
libs[opcode] = true;
this._header += '\n' + Mapping.lib[opcode] + '\n';
return true;
}
return libs[opcode];
};
AGLSLParser.prototype.parse = function (desc, precision, es300) {
if (es300 === void 0) { es300 = false; }
es300 = Settings.USE_300_SHADERS_FOR_WEBGL2 && es300;
this._usedTemps = {};
this._usedLibs = {};
this._header = '';
this._body = '';
this._header += es300 ? '#version 300 es\n' : '#version 100\n';
this._header += 'precision ' + precision + ' float;\n';
var tag = desc.header.type[0]; //TODO
var constcount = desc.regread[0x1].length;
if (constcount > 0) {
this._header += 'uniform vec4 ' + tag + 'c[' + constcount + '];\n';
}
/*
// declare temps
for (let i = 0; i < desc.regread[REGISTER.TEMP].length || i < desc.regwrite[REGISTER.TEMP].length; i++) {
// duh, have to check write only also...
if (desc.regread[REGISTER.TEMP][i] || desc.regwrite[REGISTER.TEMP][i]) {
this._header += 'vec4 ' + tag + 't' + i + ';\n';
}
}*/
// declare streams
for (var i = 0; i < desc.regread[0 /* REGISTER.ATTR */].length; i++) {
if (desc.regread[0 /* REGISTER.ATTR */][i]) {
this._header += (es300 ? 'in' : 'attribute') + ' vec4 va' + i + ';\n';
}
}
// declare interpolated
for (var i = 0; i < desc.regread[4 /* REGISTER.VAR */].length || i < desc.regwrite[4 /* REGISTER.VAR */].length; i++) {
if (desc.regread[4 /* REGISTER.VAR */][i] || desc.regwrite[4 /* REGISTER.VAR */][i]) {
if (es300) {
// in ES 300 out of vertex in of fragment
this._header += (desc.header.type === 'vertex' ? 'out' : 'in') + ' vec4 vi' + i + ';\n';
}
else {
this._header += 'varying vec4 vi' + i + ';\n';
}
}
}
// declare samplers
for (var i = 0; i < desc.samplers.length; i++) {
if (desc.samplers[i]) {
this._header += 'uniform sampler' +
AGLSLParser.SAMPLERS[desc.samplers[i].dim & 3] + ' fs' + i + ';\n';
}
}
// extra gl fluff: setup position and depth adjust temps
if (desc.header.type == 'vertex') {
this._header += 'vec4 outpos;\n';
}
else if (es300) {
// target is es300, emit out color
this._header += 'out vec4 outColor;\n';
}
if (desc.writedepth) {
this._header += 'vec4 tmp_FragDepth;\n';
}
//if ( desc.hasmatrix )
// header += "vec4 tmp_matrix;\n";
var derivatives = false;
// start body of code
this._body += 'void main() {\n';
for (var i = 0; i < desc.tokens.length; i++) {
var token = desc.tokens[i];
var lutentry = Mapping.agal2glsllut[token.opcode];
var hasLib = this._linkLib(token.opcode);
if (lutentry.s.indexOf('dFdx') != -1 || lutentry.s.indexOf('dFdy') != -1)
derivatives = true;
if (!lutentry) {
throw 'Opcode not valid or not implemented yet: ';
/*+token.opcode;*/
}
var sublines = hasLib ? 1 : lutentry.matrixheight || 1;
for (var sl = 0; sl < sublines; sl++) {
var line = ' ' + lutentry.s;
var destregstring = '';
var destcaststring = 'float';
var destmaskstring = '';
if (token.dest) {
if (lutentry.matrixheight && !hasLib) {
if (((token.dest.mask >> sl) & 1) != 1) {
continue;
}
destmaskstring = AGLSLParser.SWIZZLE[sl];
destregstring = this.regtostring(token.dest.regtype, token.dest.regnum, desc, tag, es300);
destregstring += '.' + destmaskstring;
}
else {
destregstring = this.regtostring(token.dest.regtype, token.dest.regnum, desc, tag, es300);
if (token.dest.mask != 0xf) {
var ndest = 0;
destmaskstring = '';
if (token.dest.mask & 1) {
ndest++;
destmaskstring += 'x';
}
if (token.dest.mask & 2) {
ndest++;
destmaskstring += 'y';
}
if (token.dest.mask & 4) {
ndest++;
destmaskstring += 'z';
}
if (token.dest.mask & 8) {
ndest++;
destmaskstring += 'w';
}
destregstring += '.' + destmaskstring;
switch (ndest) {
case 1:
destcaststring = 'float';
break;
case 2:
destcaststring = 'vec2';
break;
case 3:
destcaststring = 'vec3';
break;
default:
throw 'Unexpected destination mask';
}
}
else {
destcaststring = 'vec4';
destmaskstring = 'xyzw';
}
}
if (token.dest.regtype == 2 /* REGISTER.TEMP */ &&
!this._usedTemps[token.dest.regnum]) {
var tmp = tag + 't' + token.dest.regnum;
if (destcaststring === 'vec4') {
destregstring = 'vec4 ' + tmp;
}
else {
line = ' vec4 ' + tmp + ';\n' + line;
}
this._usedTemps[token.dest.regnum] = true;
}
line = line.replace('%dest', destregstring);
line = line.replace('%cast', destcaststring);
line = line.replace('%dm', destmaskstring);
}
var dwm = 0xf;
if (!lutentry.ndwm && lutentry.dest && token.dest) {
dwm = token.dest.mask;
}
if (token.a) {
line = line.replace('%a', this.sourcetostring(token.a, 0, dwm, lutentry.scalar, desc, tag, es300));
line = line.replace('%ia', '' + token.a.regnum);
}
if (token.b) {
line = line.replace('%b', this.sourcetostring(token.b, sl, dwm, lutentry.scalar, desc, tag, es300));
line = line.replace('%ib', '' + token.b.regnum);
if (token.b.regtype == 0x5) {
// sampler dim
var texdim = AGLSLParser.SAMPLERS[token.b.dim];
var texsize = ['vec2', 'vec3', 'vec3'][token.b.dim];
// for es 300 not required a texture type
line = line.replace('%texdim', es300 ? '' : texdim);
line = line.replace('%texsize', texsize);
line = line.replace('%lod', '');
}
}
this._body += line;
}
}
// adjust z from opengl range of -1..1 to 0..1 as in d3d, this also enforces a left handed coordinate system
if (desc.header.type == 'vertex') {
this._body += ' gl_Position = vec4(outpos.x, outpos.y, outpos.z*2.0 - outpos.w, outpos.w);\n';
}
//flag based switch
if (derivatives && desc.header.type == 'fragment') {
this._header = '#extension GL_OES_standard_derivatives : enable\n' + this._header;
}
// clamp fragment depth
if (desc.writedepth) {
this._body += ' gl_FragDepth = clamp(tmp_FragDepth,0.0,1.0);\n';
}
// close main
this._body += '}\n';
return this._header + this._body;
};
AGLSLParser.prototype.regtostring = function (regtype, regnum, desc, tag, es300) {
switch (regtype) {
case 0 /* REGISTER.ATTR */:
return 'va' + regnum;
case 1 /* REGISTER.CONST */:
return desc.header.type[0] + 'c[' + regnum + ']';
// case 0x1:
// if (desc.hasindirect && desc.header.type == "vertex") {
// return "vcarrr[" + regnum + "]";
// } else {
// return tag + "c" + regnum;
// }
case 2 /* REGISTER.TEMP */: {
return tag + 't' + regnum;
}
case 3 /* REGISTER.OUT */: {
if (desc.header.type == 'vertex') {
return 'outpos';
}
else if (es300) {
return 'outColor';
}
return 'gl_FragColor';
}
case 4 /* REGISTER.VAR */:
return 'vi' + regnum;
case 5 /* REGISTER.SAMPLER */:
return 'fs' + regnum;
case 15 /* REGISTER.NATIVE */: {
if (desc.native[regnum] === undefined) {
throw 'Native mapping not presented for register:' + regnum;
}
return desc.native[regnum];
}
default:
throw 'Unknown register type';
}
};
AGLSLParser.prototype.sourcetostring = function (s, subline, dwm, isscalar, desc, tag, es300) {
var swiz = AGLSLParser.SWIZZLE;
var r;
if (s.indirectflag) {
r = 'vcarrr[int(' + this.regtostring(s.indexregtype, s.regnum, desc, tag, es300) + '.' + swiz[s.indexselect] + ')';
var realofs = subline + s.indexoffset;
if (realofs < 0)
r += realofs.toString();
if (realofs > 0)
r += '+' + realofs.toString();
r += ']';
}
else {
r = this.regtostring(s.regtype, s.regnum + subline, desc, tag, es300);
}
// samplers and native never add swizzle
if (s.regtype == 5 /* REGISTER.SAMPLER */ || s.regtype == 15 /* REGISTER.NATIVE */) {
return r;
}
// scalar, first component only
if (isscalar) {
return r + '.' + swiz[(s.swizzle >> 0) & 3];
}
// identity
if (s.swizzle == 0xe4 && dwm == 0xf) {
return r;
}
// with destination write mask folded in
r += '.';
if (dwm & 1)
r += swiz[(s.swizzle >> 0) & 3];
if (dwm & 2)
r += swiz[(s.swizzle >> 2) & 3];
if (dwm & 4)
r += swiz[(s.swizzle >> 4) & 3];
if (dwm & 8)
r += swiz[(s.swizzle >> 6) & 3];
return r;
};
AGLSLParser.SWIZZLE = ['x', 'y', 'z', 'w'];
AGLSLParser.SAMPLERS = ['2D', 'Cube', '3D', ''];
AGLSLParser.maxvertexconstants = 128;
AGLSLParser.maxfragconstants = 28;
AGLSLParser.maxtemp = 8;
AGLSLParser.maxstreams = 8;
AGLSLParser.maxtextures = 8;
return AGLSLParser;
}());
export { AGLSLParser };