| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 | import defined from "../Core/defined.js";import DeveloperError from "../Core/DeveloperError.js";/** * A function to port GLSL shaders from GLSL ES 1.00 to GLSL ES 3.00 * * This function is nowhere near comprehensive or complete. It just * handles some common cases. * * Note that this function requires the presence of the * "#define OUTPUT_DECLARATION" line that is appended * by ShaderSource. * * @private */function modernizeShader(source, isFragmentShader) {  const outputDeclarationRegex = /#define OUTPUT_DECLARATION/;  const splitSource = source.split("\n");  if (/#version 300 es/g.test(source)) {    return source;  }  let outputDeclarationLine = -1;  let i, line;  for (i = 0; i < splitSource.length; ++i) {    line = splitSource[i];    if (outputDeclarationRegex.test(line)) {      outputDeclarationLine = i;      break;    }  }  if (outputDeclarationLine === -1) {    throw new DeveloperError("Could not find a #define OUTPUT_DECLARATION!");  }  const outputVariables = [];  for (i = 0; i < 10; i++) {    const fragDataString = `gl_FragData\\[${i}\\]`;    const newOutput = `czm_out${i}`;    const regex = new RegExp(fragDataString, "g");    if (regex.test(source)) {      setAdd(newOutput, outputVariables);      replaceInSourceString(fragDataString, newOutput, splitSource);      splitSource.splice(        outputDeclarationLine,        0,        `layout(location = ${i}) out vec4 ${newOutput};`      );      outputDeclarationLine += 1;    }  }  const czmFragColor = "czm_fragColor";  if (findInSource("gl_FragColor", splitSource)) {    setAdd(czmFragColor, outputVariables);    replaceInSourceString("gl_FragColor", czmFragColor, splitSource);    splitSource.splice(      outputDeclarationLine,      0,      "layout(location = 0) out vec4 czm_fragColor;"    );    outputDeclarationLine += 1;  }  const variableMap = getVariablePreprocessorBranch(    outputVariables,    splitSource  );  const lineAdds = {};  for (i = 0; i < splitSource.length; i++) {    line = splitSource[i];    for (const variable in variableMap) {      if (variableMap.hasOwnProperty(variable)) {        const matchVar = new RegExp(          `(layout)[^]+(out)[^]+(${variable})[^]+`,          "g"        );        if (matchVar.test(line)) {          lineAdds[line] = variable;        }      }    }  }  for (const layoutDeclaration in lineAdds) {    if (lineAdds.hasOwnProperty(layoutDeclaration)) {      const variableName = lineAdds[layoutDeclaration];      let lineNumber = splitSource.indexOf(layoutDeclaration);      const entry = variableMap[variableName];      const depth = entry.length;      for (let d = 0; d < depth; d++) {        splitSource.splice(lineNumber, 0, entry[d]);      }      lineNumber += depth + 1;      for (let d = depth - 1; d >= 0; d--) {        splitSource.splice(lineNumber, 0, `#endif //${entry[d]}`);      }    }  }  const webgl2UniqueID = "WEBGL_2";  const webgl2DefineMacro = `#define ${webgl2UniqueID}`;  const versionThree = "#version 300 es";  let foundVersion = false;  for (i = 0; i < splitSource.length; i++) {    if (/#version/.test(splitSource[i])) {      splitSource[i] = versionThree;      foundVersion = true;      break;    }  }  if (!foundVersion) {    splitSource.splice(0, 0, versionThree);  }  splitSource.splice(1, 0, webgl2DefineMacro);  removeExtension("EXT_draw_buffers", webgl2UniqueID, splitSource);  removeExtension("EXT_frag_depth", webgl2UniqueID, splitSource);  removeExtension("OES_standard_derivatives", webgl2UniqueID, splitSource);  replaceInSourceString("texture2D", "texture", splitSource);  replaceInSourceString("texture3D", "texture", splitSource);  replaceInSourceString("textureCube", "texture", splitSource);  replaceInSourceString("gl_FragDepthEXT", "gl_FragDepth", splitSource);  if (isFragmentShader) {    replaceInSourceString("varying", "in", splitSource);  } else {    replaceInSourceString("attribute", "in", splitSource);    replaceInSourceString("varying", "out", splitSource);  }  return compileSource(splitSource);}// Note that this fails if your string looks like// searchString[singleCharacter]searchStringfunction replaceInSourceString(str, replacement, splitSource) {  const regexStr = `(^|[^\\w])(${str})($|[^\\w])`;  const regex = new RegExp(regexStr, "g");  const splitSourceLength = splitSource.length;  for (let i = 0; i < splitSourceLength; ++i) {    const line = splitSource[i];    splitSource[i] = line.replace(regex, `$1${replacement}$3`);  }}function replaceInSourceRegex(regex, replacement, splitSource) {  const splitSourceLength = splitSource.length;  for (let i = 0; i < splitSourceLength; ++i) {    const line = splitSource[i];    splitSource[i] = line.replace(regex, replacement);  }}function findInSource(str, splitSource) {  const regexStr = `(^|[^\\w])(${str})($|[^\\w])`;  const regex = new RegExp(regexStr, "g");  const splitSourceLength = splitSource.length;  for (let i = 0; i < splitSourceLength; ++i) {    const line = splitSource[i];    if (regex.test(line)) {      return true;    }  }  return false;}function compileSource(splitSource) {  let wholeSource = "";  const splitSourceLength = splitSource.length;  for (let i = 0; i < splitSourceLength; ++i) {    wholeSource += `${splitSource[i]}\n`;  }  return wholeSource;}function setAdd(variable, set) {  if (set.indexOf(variable) === -1) {    set.push(variable);  }}function getVariablePreprocessorBranch(layoutVariables, splitSource) {  const variableMap = {};  const numLayoutVariables = layoutVariables.length;  const stack = [];  for (let i = 0; i < splitSource.length; ++i) {    const line = splitSource[i];    const hasIF = /(#ifdef|#if)/g.test(line);    const hasELSE = /#else/g.test(line);    const hasENDIF = /#endif/g.test(line);    if (hasIF) {      stack.push(line);    } else if (hasELSE) {      const top = stack[stack.length - 1];      let op = top.replace("ifdef", "ifndef");      if (/if/g.test(op)) {        op = op.replace(/(#if\s+)(\S*)([^]*)/, "$1!($2)$3");      }      stack.pop();      stack.push(op);    } else if (hasENDIF) {      stack.pop();    } else if (!/layout/g.test(line)) {      for (let varIndex = 0; varIndex < numLayoutVariables; ++varIndex) {        const varName = layoutVariables[varIndex];        if (line.indexOf(varName) !== -1) {          if (!defined(variableMap[varName])) {            variableMap[varName] = stack.slice();          } else {            variableMap[varName] = variableMap[varName].filter(function (x) {              return stack.indexOf(x) >= 0;            });          }        }      }    }  }  return variableMap;}function removeExtension(name, webgl2UniqueID, splitSource) {  const regex = `#extension\\s+GL_${name}\\s+:\\s+[a-zA-Z0-9]+\\s*$`;  replaceInSourceRegex(new RegExp(regex, "g"), "", splitSource);  // replace any possible directive #ifdef (GL_EXT_extension) with WEBGL_2 unique directive  replaceInSourceString(`GL_${name}`, webgl2UniqueID, splitSource);}export default modernizeShader;
 |