@luma.gl/shadertools
Version:
Shader module system for luma.gl
1,704 lines (1,623 loc) • 135 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
// dist/index.js
var dist_exports = {};
__export(dist_exports, {
ShaderAssembler: () => ShaderAssembler,
_getDependencyGraph: () => getDependencyGraph,
_resolveModules: () => resolveModules,
assembleGLSLShaderPair: () => assembleGLSLShaderPair,
capitalize: () => capitalize,
checkShaderModuleDeprecations: () => checkShaderModuleDeprecations,
combineInjects: () => combineInjects,
convertToVec4: () => convertToVec4,
dirlight: () => dirlight,
dirlight1: () => dirlight2,
fp32: () => fp32,
fp64: () => fp64,
fp64LowPart: () => fp64LowPart,
fp64arithmetic: () => fp64arithmetic,
fp64ify: () => fp64ify,
fp64ifyMatrix4: () => fp64ifyMatrix4,
fromHalfFloat: () => fromHalfFloat,
generateShaderForModule: () => generateShaderForModule,
geometry1: () => geometry,
getPassthroughFS: () => getPassthroughFS,
getQualifierDetails: () => getQualifierDetails,
getShaderInfo: () => getShaderInfo,
getShaderLayoutFromWGSL: () => getShaderLayoutFromWGSL,
getShaderModuleDependencies: () => getShaderModuleDependencies,
getShaderModuleSource: () => getShaderModuleSource,
getShaderModuleUniforms: () => getShaderModuleUniforms,
gouraudLighting: () => gouraudLighting,
gouraudMaterial: () => gouraudMaterial,
initializeShaderModule: () => initializeShaderModule,
initializeShaderModules: () => initializeShaderModules,
lighting: () => lighting,
lights1: () => lights,
pbr: () => pbr,
pbrMaterial: () => pbrMaterial,
phongLighting: () => phongLighting,
phongMaterial: () => phongMaterial,
picking: () => picking,
preprocess: () => preprocess,
project1: () => project,
random: () => random,
toHalfFloat: () => toHalfFloat,
typeToChannelCount: () => typeToChannelCount,
typeToChannelSuffix: () => typeToChannelSuffix
});
module.exports = __toCommonJS(dist_exports);
// dist/lib/utils/assert.js
function assert(condition, message) {
if (!condition) {
throw new Error(message || "shadertools: assertion failed.");
}
}
// dist/lib/filters/prop-types.js
var DEFAULT_PROP_VALIDATORS = {
number: {
type: "number",
validate(value, propType) {
return Number.isFinite(value) && typeof propType === "object" && (propType.max === void 0 || value <= propType.max) && (propType.min === void 0 || value >= propType.min);
}
},
array: {
type: "array",
validate(value, propType) {
return Array.isArray(value) || ArrayBuffer.isView(value);
}
}
};
function makePropValidators(propTypes) {
const propValidators = {};
for (const [name, propType] of Object.entries(propTypes)) {
propValidators[name] = makePropValidator(propType);
}
return propValidators;
}
function getValidatedProperties(properties, propValidators, errorMessage) {
const validated = {};
for (const [key, propsValidator] of Object.entries(propValidators)) {
if (properties && key in properties && !propsValidator.private) {
if (propsValidator.validate) {
assert(propsValidator.validate(properties[key], propsValidator), `${errorMessage}: invalid ${key}`);
}
validated[key] = properties[key];
} else {
validated[key] = propsValidator.value;
}
}
return validated;
}
function makePropValidator(propType) {
let type = getTypeOf(propType);
if (type !== "object") {
return { value: propType, ...DEFAULT_PROP_VALIDATORS[type], type };
}
if (typeof propType === "object") {
if (!propType) {
return { type: "object", value: null };
}
if (propType.type !== void 0) {
return { ...propType, ...DEFAULT_PROP_VALIDATORS[propType.type], type: propType.type };
}
if (propType.value === void 0) {
return { type: "object", value: propType };
}
type = getTypeOf(propType.value);
return { ...propType, ...DEFAULT_PROP_VALIDATORS[type], type };
}
throw new Error("props");
}
function getTypeOf(value) {
if (Array.isArray(value) || ArrayBuffer.isView(value)) {
return "array";
}
return typeof value;
}
// dist/module-injectors.js
var MODULE_INJECTORS_VS = (
/* glsl */
`#ifdef MODULE_LOGDEPTH
logdepth_adjustPosition(gl_Position);
#endif
`
);
var MODULE_INJECTORS_FS = (
/* glsl */
`#ifdef MODULE_MATERIAL
fragColor = material_filterColor(fragColor);
#endif
#ifdef MODULE_LIGHTING
fragColor = lighting_filterColor(fragColor);
#endif
#ifdef MODULE_FOG
fragColor = fog_filterColor(fragColor);
#endif
#ifdef MODULE_PICKING
fragColor = picking_filterHighlightColor(fragColor);
fragColor = picking_filterPickingColor(fragColor);
#endif
#ifdef MODULE_LOGDEPTH
logdepth_setFragDepth();
#endif
`
);
// dist/lib/shader-assembly/shader-injections.js
var MODULE_INJECTORS = {
vertex: MODULE_INJECTORS_VS,
fragment: MODULE_INJECTORS_FS
};
var REGEX_START_OF_MAIN = /void\s+main\s*\([^)]*\)\s*\{\n?/;
var REGEX_END_OF_MAIN = /}\n?[^{}]*$/;
var fragments = [];
var DECLARATION_INJECT_MARKER = "__LUMA_INJECT_DECLARATIONS__";
function normalizeInjections(injections) {
const result = { vertex: {}, fragment: {} };
for (const hook in injections) {
let injection = injections[hook];
const stage = getHookStage(hook);
if (typeof injection === "string") {
injection = {
order: 0,
injection
};
}
result[stage][hook] = injection;
}
return result;
}
function getHookStage(hook) {
const type = hook.slice(0, 2);
switch (type) {
case "vs":
return "vertex";
case "fs":
return "fragment";
default:
throw new Error(type);
}
}
function injectShader(source, stage, inject, injectStandardStubs = false) {
const isVertex = stage === "vertex";
for (const key in inject) {
const fragmentData = inject[key];
fragmentData.sort((a, b) => a.order - b.order);
fragments.length = fragmentData.length;
for (let i = 0, len = fragmentData.length; i < len; ++i) {
fragments[i] = fragmentData[i].injection;
}
const fragmentString = `${fragments.join("\n")}
`;
switch (key) {
case "vs:#decl":
if (isVertex) {
source = source.replace(DECLARATION_INJECT_MARKER, fragmentString);
}
break;
case "vs:#main-start":
if (isVertex) {
source = source.replace(REGEX_START_OF_MAIN, (match) => match + fragmentString);
}
break;
case "vs:#main-end":
if (isVertex) {
source = source.replace(REGEX_END_OF_MAIN, (match) => fragmentString + match);
}
break;
case "fs:#decl":
if (!isVertex) {
source = source.replace(DECLARATION_INJECT_MARKER, fragmentString);
}
break;
case "fs:#main-start":
if (!isVertex) {
source = source.replace(REGEX_START_OF_MAIN, (match) => match + fragmentString);
}
break;
case "fs:#main-end":
if (!isVertex) {
source = source.replace(REGEX_END_OF_MAIN, (match) => fragmentString + match);
}
break;
default:
source = source.replace(key, (match) => match + fragmentString);
}
}
source = source.replace(DECLARATION_INJECT_MARKER, "");
if (injectStandardStubs) {
source = source.replace(/\}\s*$/, (match) => match + MODULE_INJECTORS[stage]);
}
return source;
}
function combineInjects(injects) {
const result = {};
assert(Array.isArray(injects) && injects.length > 1);
injects.forEach((inject) => {
for (const key in inject) {
result[key] = result[key] ? `${result[key]}
${inject[key]}` : inject[key];
}
});
return result;
}
// dist/lib/shader-module/shader-module.js
function initializeShaderModules(modules) {
modules.map((module2) => initializeShaderModule(module2));
}
function initializeShaderModule(module2) {
if (module2.instance) {
return;
}
initializeShaderModules(module2.dependencies || []);
const {
propTypes = {},
deprecations = [],
// defines = {},
inject = {}
} = module2;
const instance = {
normalizedInjections: normalizeInjections(inject),
parsedDeprecations: parseDeprecationDefinitions(deprecations)
};
if (propTypes) {
instance.propValidators = makePropValidators(propTypes);
}
module2.instance = instance;
let defaultProps = {};
if (propTypes) {
defaultProps = Object.entries(propTypes).reduce((obj, [key, propType]) => {
const value = propType == null ? void 0 : propType.value;
if (value) {
obj[key] = value;
}
return obj;
}, {});
}
module2.defaultUniforms = { ...module2.defaultUniforms, ...defaultProps };
}
function getShaderModuleUniforms(module2, props, oldUniforms) {
var _a;
initializeShaderModule(module2);
const uniforms = oldUniforms || { ...module2.defaultUniforms };
if (props && module2.getUniforms) {
return module2.getUniforms(props, uniforms);
}
return getValidatedProperties(props, (_a = module2.instance) == null ? void 0 : _a.propValidators, module2.name);
}
function checkShaderModuleDeprecations(shaderModule, shaderSource, log3) {
var _a;
(_a = shaderModule.deprecations) == null ? void 0 : _a.forEach((def) => {
var _a2;
if ((_a2 = def.regex) == null ? void 0 : _a2.test(shaderSource)) {
if (def.deprecated) {
log3.deprecated(def.old, def.new)();
} else {
log3.removed(def.old, def.new)();
}
}
});
}
function parseDeprecationDefinitions(deprecations) {
deprecations.forEach((def) => {
switch (def.type) {
case "function":
def.regex = new RegExp(`\\b${def.old}\\(`);
break;
default:
def.regex = new RegExp(`${def.type} ${def.old};`);
}
});
return deprecations;
}
// dist/lib/shader-module/shader-module-dependencies.js
function getShaderModuleDependencies(modules) {
initializeShaderModules(modules);
const moduleMap = {};
const moduleDepth = {};
getDependencyGraph({ modules, level: 0, moduleMap, moduleDepth });
const dependencies = Object.keys(moduleDepth).sort((a, b) => moduleDepth[b] - moduleDepth[a]).map((name) => moduleMap[name]);
initializeShaderModules(dependencies);
return dependencies;
}
function getDependencyGraph(options) {
const { modules, level, moduleMap, moduleDepth } = options;
if (level >= 5) {
throw new Error("Possible loop in shader dependency graph");
}
for (const module2 of modules) {
moduleMap[module2.name] = module2;
if (moduleDepth[module2.name] === void 0 || moduleDepth[module2.name] < level) {
moduleDepth[module2.name] = level;
}
}
for (const module2 of modules) {
if (module2.dependencies) {
getDependencyGraph({ modules: module2.dependencies, level: level + 1, moduleMap, moduleDepth });
}
}
}
function getShaderDependencies(modules) {
initializeShaderModules(modules);
const moduleMap = {};
const moduleDepth = {};
getDependencyGraph({ modules, level: 0, moduleMap, moduleDepth });
modules = Object.keys(moduleDepth).sort((a, b) => moduleDepth[b] - moduleDepth[a]).map((name) => moduleMap[name]);
initializeShaderModules(modules);
return modules;
}
function resolveModules(modules) {
return getShaderDependencies(modules);
}
// dist/lib/shader-assembly/platform-defines.js
function getPlatformShaderDefines(platformInfo) {
switch (platformInfo == null ? void 0 : platformInfo.gpu.toLowerCase()) {
case "apple":
return (
/* glsl */
`#define APPLE_GPU
// Apple optimizes away the calculation necessary for emulated fp64
#define LUMA_FP64_CODE_ELIMINATION_WORKAROUND 1
#define LUMA_FP32_TAN_PRECISION_WORKAROUND 1
// Intel GPU doesn't have full 32 bits precision in same cases, causes overflow
#define LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND 1
`
);
case "nvidia":
return (
/* glsl */
`#define NVIDIA_GPU
// Nvidia optimizes away the calculation necessary for emulated fp64
#define LUMA_FP64_CODE_ELIMINATION_WORKAROUND 1
`
);
case "intel":
return (
/* glsl */
`#define INTEL_GPU
// Intel optimizes away the calculation necessary for emulated fp64
#define LUMA_FP64_CODE_ELIMINATION_WORKAROUND 1
// Intel's built-in 'tan' function doesn't have acceptable precision
#define LUMA_FP32_TAN_PRECISION_WORKAROUND 1
// Intel GPU doesn't have full 32 bits precision in same cases, causes overflow
#define LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND 1
`
);
case "amd":
return (
/* glsl */
`#define AMD_GPU
`
);
default:
return (
/* glsl */
`#define DEFAULT_GPU
// Prevent driver from optimizing away the calculation necessary for emulated fp64
#define LUMA_FP64_CODE_ELIMINATION_WORKAROUND 1
// Headless Chrome's software shader 'tan' function doesn't have acceptable precision
#define LUMA_FP32_TAN_PRECISION_WORKAROUND 1
// If the GPU doesn't have full 32 bits precision, will causes overflow
#define LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND 1
`
);
}
}
// dist/lib/shader-transpiler/transpile-glsl-shader.js
function transpileGLSLShader(source, stage) {
var _a;
const sourceGLSLVersion = Number(((_a = source.match(/^#version[ \t]+(\d+)/m)) == null ? void 0 : _a[1]) || 100);
if (sourceGLSLVersion !== 300) {
throw new Error("luma.gl v9 only supports GLSL 3.00 shader sources");
}
switch (stage) {
case "vertex":
source = convertShader(source, ES300_VERTEX_REPLACEMENTS);
return source;
case "fragment":
source = convertShader(source, ES300_FRAGMENT_REPLACEMENTS);
return source;
default:
throw new Error(stage);
}
}
var ES300_REPLACEMENTS = [
// Fix poorly formatted version directive
[/^(#version[ \t]+(100|300[ \t]+es))?[ \t]*\n/, "#version 300 es\n"],
// The individual `texture...()` functions were replaced with `texture()` overloads
[/\btexture(2D|2DProj|Cube)Lod(EXT)?\(/g, "textureLod("],
[/\btexture(2D|2DProj|Cube)(EXT)?\(/g, "texture("]
];
var ES300_VERTEX_REPLACEMENTS = [
...ES300_REPLACEMENTS,
// `attribute` keyword replaced with `in`
[makeVariableTextRegExp("attribute"), "in $1"],
// `varying` keyword replaced with `out`
[makeVariableTextRegExp("varying"), "out $1"]
];
var ES300_FRAGMENT_REPLACEMENTS = [
...ES300_REPLACEMENTS,
// `varying` keyword replaced with `in`
[makeVariableTextRegExp("varying"), "in $1"]
];
function convertShader(source, replacements) {
for (const [pattern, replacement] of replacements) {
source = source.replace(pattern, replacement);
}
return source;
}
function makeVariableTextRegExp(qualifier) {
return new RegExp(`\\b${qualifier}[ \\t]+(\\w+[ \\t]+\\w+(\\[\\w+\\])?;)`, "g");
}
// dist/lib/shader-assembly/shader-hooks.js
function getShaderHooks(hookFunctions, hookInjections) {
let result = "";
for (const hookName in hookFunctions) {
const hookFunction = hookFunctions[hookName];
result += `void ${hookFunction.signature} {
`;
if (hookFunction.header) {
result += ` ${hookFunction.header}`;
}
if (hookInjections[hookName]) {
const injections = hookInjections[hookName];
injections.sort((a, b) => a.order - b.order);
for (const injection of injections) {
result += ` ${injection.injection}
`;
}
}
if (hookFunction.footer) {
result += ` ${hookFunction.footer}`;
}
result += "}\n";
}
return result;
}
function normalizeShaderHooks(hookFunctions) {
const result = { vertex: {}, fragment: {} };
for (const hookFunction of hookFunctions) {
let opts;
let hook;
if (typeof hookFunction !== "string") {
opts = hookFunction;
hook = opts.hook;
} else {
opts = {};
hook = hookFunction;
}
hook = hook.trim();
const [shaderStage, signature] = hook.split(":");
const name = hook.replace(/\(.+/, "");
const normalizedHook = Object.assign(opts, { signature });
switch (shaderStage) {
case "vs":
result.vertex[name] = normalizedHook;
break;
case "fs":
result.fragment[name] = normalizedHook;
break;
default:
throw new Error(shaderStage);
}
}
return result;
}
// dist/lib/glsl-utils/get-shader-info.js
function getShaderInfo(source, defaultName) {
return {
name: getShaderName(source, defaultName),
language: "glsl",
version: getShaderVersion(source)
};
}
function getShaderName(shader, defaultName = "unnamed") {
const SHADER_NAME_REGEXP = /#define[^\S\r\n]*SHADER_NAME[^\S\r\n]*([A-Za-z0-9_-]+)\s*/;
const match = SHADER_NAME_REGEXP.exec(shader);
return match ? match[1] : defaultName;
}
function getShaderVersion(source) {
let version = 100;
const words = source.match(/[^\s]+/g);
if (words && words.length >= 2 && words[0] === "#version") {
const parsedVersion = parseInt(words[1], 10);
if (Number.isFinite(parsedVersion)) {
version = parsedVersion;
}
}
if (version !== 100 && version !== 300) {
throw new Error(`Invalid GLSL version ${version}`);
}
return version;
}
// dist/lib/shader-assembly/assemble-shaders.js
var INJECT_SHADER_DECLARATIONS = `
${DECLARATION_INJECT_MARKER}
`;
var FRAGMENT_SHADER_PROLOGUE = (
/* glsl */
`precision highp float;
`
);
function assembleWGSLShader(options) {
const modules = getShaderModuleDependencies(options.modules || []);
return {
source: assembleShaderWGSL(options.platformInfo, {
...options,
source: options.source,
stage: "vertex",
modules
}),
getUniforms: assembleGetUniforms(modules)
};
}
function assembleGLSLShaderPair(options) {
const { vs: vs6, fs: fs8 } = options;
const modules = getShaderModuleDependencies(options.modules || []);
return {
vs: assembleShaderGLSL(options.platformInfo, {
...options,
source: vs6,
stage: "vertex",
modules
}),
fs: assembleShaderGLSL(options.platformInfo, {
...options,
// @ts-expect-error
source: fs8,
stage: "fragment",
modules
}),
getUniforms: assembleGetUniforms(modules)
};
}
function assembleShaderWGSL(platformInfo, options) {
var _a;
const {
// id,
source,
stage,
modules,
// defines = {},
hookFunctions = [],
inject = {},
log: log3
} = options;
assert(typeof source === "string", "shader source must be a string");
const coreSource = source;
let assembledSource = "";
const hookFunctionMap = normalizeShaderHooks(hookFunctions);
const hookInjections = {};
const declInjections = {};
const mainInjections = {};
for (const key in inject) {
const injection = typeof inject[key] === "string" ? { injection: inject[key], order: 0 } : inject[key];
const match = /^(v|f)s:(#)?([\w-]+)$/.exec(key);
if (match) {
const hash = match[2];
const name = match[3];
if (hash) {
if (name === "decl") {
declInjections[key] = [injection];
} else {
mainInjections[key] = [injection];
}
} else {
hookInjections[key] = [injection];
}
} else {
mainInjections[key] = [injection];
}
}
const modulesToInject = modules;
for (const module2 of modulesToInject) {
if (log3) {
checkShaderModuleDeprecations(module2, coreSource, log3);
}
const moduleSource = getShaderModuleSource(module2, "wgsl");
assembledSource += moduleSource;
const injections = ((_a = module2.injections) == null ? void 0 : _a[stage]) || {};
for (const key in injections) {
const match = /^(v|f)s:#([\w-]+)$/.exec(key);
if (match) {
const name = match[2];
const injectionType = name === "decl" ? declInjections : mainInjections;
injectionType[key] = injectionType[key] || [];
injectionType[key].push(injections[key]);
} else {
hookInjections[key] = hookInjections[key] || [];
hookInjections[key].push(injections[key]);
}
}
}
assembledSource += INJECT_SHADER_DECLARATIONS;
assembledSource = injectShader(assembledSource, stage, declInjections);
assembledSource += getShaderHooks(hookFunctionMap[stage], hookInjections);
assembledSource += coreSource;
assembledSource = injectShader(assembledSource, stage, mainInjections);
return assembledSource;
}
function assembleShaderGLSL(platformInfo, options) {
var _a;
const { id, source, stage, language = "glsl", modules, defines = {}, hookFunctions = [], inject = {}, prologue = true, log: log3 } = options;
assert(typeof source === "string", "shader source must be a string");
const sourceVersion = language === "glsl" ? getShaderInfo(source).version : -1;
const targetVersion = platformInfo.shaderLanguageVersion;
const sourceVersionDirective = sourceVersion === 100 ? "#version 100" : "#version 300 es";
const sourceLines = source.split("\n");
const coreSource = sourceLines.slice(1).join("\n");
const allDefines = {};
modules.forEach((module2) => {
Object.assign(allDefines, module2.defines);
});
Object.assign(allDefines, defines);
let assembledSource = "";
switch (language) {
case "wgsl":
break;
case "glsl":
assembledSource = prologue ? `${sourceVersionDirective}
// ----- PROLOGUE -------------------------
${getShaderNameDefine({ id, source, stage })}
${`#define SHADER_TYPE_${stage.toUpperCase()}`}
${getPlatformShaderDefines(platformInfo)}
${stage === "fragment" ? FRAGMENT_SHADER_PROLOGUE : ""}
// ----- APPLICATION DEFINES -------------------------
${getApplicationDefines(allDefines)}
` : `${sourceVersionDirective}
`;
break;
}
const hookFunctionMap = normalizeShaderHooks(hookFunctions);
const hookInjections = {};
const declInjections = {};
const mainInjections = {};
for (const key in inject) {
const injection = typeof inject[key] === "string" ? { injection: inject[key], order: 0 } : inject[key];
const match = /^(v|f)s:(#)?([\w-]+)$/.exec(key);
if (match) {
const hash = match[2];
const name = match[3];
if (hash) {
if (name === "decl") {
declInjections[key] = [injection];
} else {
mainInjections[key] = [injection];
}
} else {
hookInjections[key] = [injection];
}
} else {
mainInjections[key] = [injection];
}
}
for (const module2 of modules) {
if (log3) {
checkShaderModuleDeprecations(module2, coreSource, log3);
}
const moduleSource = getShaderModuleSource(module2, stage);
assembledSource += moduleSource;
const injections = ((_a = module2.instance) == null ? void 0 : _a.normalizedInjections[stage]) || {};
for (const key in injections) {
const match = /^(v|f)s:#([\w-]+)$/.exec(key);
if (match) {
const name = match[2];
const injectionType = name === "decl" ? declInjections : mainInjections;
injectionType[key] = injectionType[key] || [];
injectionType[key].push(injections[key]);
} else {
hookInjections[key] = hookInjections[key] || [];
hookInjections[key].push(injections[key]);
}
}
}
assembledSource += "// ----- MAIN SHADER SOURCE -------------------------";
assembledSource += INJECT_SHADER_DECLARATIONS;
assembledSource = injectShader(assembledSource, stage, declInjections);
assembledSource += getShaderHooks(hookFunctionMap[stage], hookInjections);
assembledSource += coreSource;
assembledSource = injectShader(assembledSource, stage, mainInjections);
if (language === "glsl" && sourceVersion !== targetVersion) {
assembledSource = transpileGLSLShader(assembledSource, stage);
}
return assembledSource.trim();
}
function assembleGetUniforms(modules) {
return function getUniforms8(opts) {
var _a;
const uniforms = {};
for (const module2 of modules) {
const moduleUniforms = (_a = module2.getUniforms) == null ? void 0 : _a.call(module2, opts, uniforms);
Object.assign(uniforms, moduleUniforms);
}
return uniforms;
};
}
function getShaderNameDefine(options) {
const { id, source, stage } = options;
const injectShaderName = id && source.indexOf("SHADER_NAME") === -1;
return injectShaderName ? `
#define SHADER_NAME ${id}_${stage}` : "";
}
function getApplicationDefines(defines = {}) {
let sourceText = "";
for (const define in defines) {
const value = defines[define];
if (value || Number.isFinite(value)) {
sourceText += `#define ${define.toUpperCase()} ${defines[define]}
`;
}
}
return sourceText;
}
function getShaderModuleSource(module2, stage) {
let moduleSource;
switch (stage) {
case "vertex":
moduleSource = module2.vs || "";
break;
case "fragment":
moduleSource = module2.fs || "";
break;
case "wgsl":
moduleSource = module2.source || "";
break;
default:
assert(false);
}
if (!module2.name) {
throw new Error("Shader module must have a name");
}
const moduleName = module2.name.toUpperCase().replace(/[^0-9a-z]/gi, "_");
let source = `// ----- MODULE ${module2.name} ---------------
`;
if (stage !== "wgsl") {
source += `#define MODULE_${moduleName}
`;
}
source += `${moduleSource}
`;
return source;
}
// dist/lib/preprocessor/preprocessor.js
var IFDEF_REGEXP = /^\s*\#\s*ifdef\s*([a-zA-Z_]+)\s*$/;
var ENDIF_REGEXP = /^\s*\#\s*endif\s*$/;
function preprocess(source, options) {
var _a;
const lines = source.split("\n");
const output = [];
let conditional = true;
let currentDefine = null;
for (const line of lines) {
const matchIf = line.match(IFDEF_REGEXP);
const matchEnd = line.match(ENDIF_REGEXP);
if (matchIf) {
currentDefine = matchIf[1];
conditional = Boolean((_a = options == null ? void 0 : options.defines) == null ? void 0 : _a[currentDefine]);
} else if (matchEnd) {
conditional = true;
} else if (conditional) {
output.push(line);
}
}
return output.join("\n");
}
// dist/lib/shader-assembler.js
var _ShaderAssembler = class {
/** Hook functions */
_hookFunctions = [];
/** Shader modules */
_defaultModules = [];
/**
* A default shader assembler instance - the natural place to register default modules and hooks
* @returns
*/
static getDefaultShaderAssembler() {
_ShaderAssembler.defaultShaderAssembler = _ShaderAssembler.defaultShaderAssembler || new _ShaderAssembler();
return _ShaderAssembler.defaultShaderAssembler;
}
/**
* Add a default module that does not have to be provided with every call to assembleShaders()
*/
addDefaultModule(module2) {
if (!this._defaultModules.find((m) => m.name === (typeof module2 === "string" ? module2 : module2.name))) {
this._defaultModules.push(module2);
}
}
/**
* Remove a default module
*/
removeDefaultModule(module2) {
const moduleName = typeof module2 === "string" ? module2 : module2.name;
this._defaultModules = this._defaultModules.filter((m) => m.name !== moduleName);
}
/**
* Register a shader hook
* @param hook
* @param opts
*/
addShaderHook(hook, opts) {
if (opts) {
hook = Object.assign(opts, { hook });
}
this._hookFunctions.push(hook);
}
/**
* Assemble a WGSL unified shader
* @param platformInfo
* @param props
* @returns
*/
assembleWGSLShader(props) {
const modules = this._getModuleList(props.modules);
const hookFunctions = this._hookFunctions;
const { source, getUniforms: getUniforms8 } = assembleWGSLShader({
...props,
// @ts-expect-error
source: props.source,
modules,
hookFunctions
});
const preprocessedSource = props.platformInfo.shaderLanguage === "wgsl" ? preprocess(source) : source;
return { source: preprocessedSource, getUniforms: getUniforms8, modules };
}
/**
* Assemble a pair of shaders into a single shader program
* @param platformInfo
* @param props
* @returns
*/
assembleGLSLShaderPair(props) {
const modules = this._getModuleList(props.modules);
const hookFunctions = this._hookFunctions;
const assembled = assembleGLSLShaderPair({
...props,
// @ts-expect-error
vs: props.vs,
// @ts-expect-error
fs: props.fs,
modules,
hookFunctions
});
return { ...assembled, modules };
}
/**
* Dedupe and combine with default modules
*/
_getModuleList(appModules = []) {
const modules = new Array(this._defaultModules.length + appModules.length);
const seen = {};
let count = 0;
for (let i = 0, len = this._defaultModules.length; i < len; ++i) {
const module2 = this._defaultModules[i];
const name = module2.name;
modules[count++] = module2;
seen[name] = true;
}
for (let i = 0, len = appModules.length; i < len; ++i) {
const module2 = appModules[i];
const name = module2.name;
if (!seen[name]) {
modules[count++] = module2;
seen[name] = true;
}
}
modules.length = count;
initializeShaderModules(modules);
return modules;
}
};
var ShaderAssembler = _ShaderAssembler;
/** Default ShaderAssembler instance */
__publicField(ShaderAssembler, "defaultShaderAssembler");
// dist/lib/glsl-utils/shader-utils.js
var FS_GLES = (
/* glsl */
`out vec4 transform_output;
void main() {
transform_output = vec4(0);
}`
);
var FS300 = `#version 300 es
${FS_GLES}`;
function getQualifierDetails(line, qualifiers) {
qualifiers = Array.isArray(qualifiers) ? qualifiers : [qualifiers];
const words = line.replace(/^\s+/, "").split(/\s+/);
const [qualifier, type, definition] = words;
if (!qualifiers.includes(qualifier) || !type || !definition) {
return null;
}
const name = definition.split(";")[0];
return { qualifier, type, name };
}
function getPassthroughFS(options) {
const { input, inputChannels, output } = options || {};
if (!input) {
return FS300;
}
if (!inputChannels) {
throw new Error("inputChannels");
}
const inputType = channelCountToType(inputChannels);
const outputValue = convertToVec4(input, inputChannels);
return `#version 300 es
in ${inputType} ${input};
out vec4 ${output};
void main() {
${output} = ${outputValue};
}`;
}
function typeToChannelSuffix(type) {
switch (type) {
case "float":
return "x";
case "vec2":
return "xy";
case "vec3":
return "xyz";
case "vec4":
return "xyzw";
default:
throw new Error(type);
}
}
function typeToChannelCount(type) {
switch (type) {
case "float":
return 1;
case "vec2":
return 2;
case "vec3":
return 3;
case "vec4":
return 4;
default:
throw new Error(type);
}
}
function channelCountToType(channels) {
switch (channels) {
case 1:
return "float";
case 2:
return "vec2";
case 3:
return "vec3";
case 4:
return "vec4";
default:
throw new Error(`invalid channels: ${channels}`);
}
}
function convertToVec4(variable, channels) {
switch (channels) {
case 1:
return `vec4(${variable}, 0.0, 0.0, 1.0)`;
case 2:
return `vec4(${variable}, 0.0, 1.0)`;
case 3:
return `vec4(${variable}, 1.0)`;
case 4:
return variable;
default:
throw new Error(`invalid channels: ${channels}`);
}
}
// dist/lib/shader-generator/utils/capitalize.js
function capitalize(str) {
return typeof str === "string" ? str.charAt(0).toUpperCase() + str.slice(1) : str;
}
// dist/lib/shader-generator/glsl/generate-glsl.js
function generateGLSLForModule(module2, options) {
return generateGLSLUniformDeclarations(module2, options);
}
function generateGLSLUniformDeclarations(module2, options) {
const glsl = [];
switch (options.uniforms) {
case "scoped-interface-blocks":
case "unscoped-interface-blocks":
glsl.push(`uniform ${capitalize(module2.name)} {`);
break;
case "uniforms":
}
for (const [uniformName, uniformFormat] of Object.entries(module2.uniformTypes || {})) {
const glslUniformType = getGLSLUniformType(uniformFormat);
switch (options.uniforms) {
case "scoped-interface-blocks":
glsl.push(` ${glslUniformType} ${uniformName};`);
break;
case "unscoped-interface-blocks":
glsl.push(` ${glslUniformType} ${module2.name}_${uniformName};`);
break;
case "uniforms":
glsl.push(`uniform ${glslUniformType} ${module2.name}_${uniformName};`);
}
}
switch (options.uniforms) {
case "scoped-interface-blocks":
glsl.push(`} ${module2.name};`);
break;
case "unscoped-interface-blocks":
glsl.push("};");
break;
case "uniforms":
}
glsl.push("");
return glsl.join("\n");
}
function getGLSLUniformType(uniformFormat) {
const UNIFORM_TYPE_TO_GLSL = {
f32: "float",
i32: "int",
u32: "uint",
"vec2<f32>": "vec2",
"vec3<f32>": "vec3",
"vec4<f32>": "vec4",
"vec2<i32>": "ivec2",
"vec3<i32>": "ivec3",
"vec4<i32>": "ivec4",
"vec2<u32>": "uvec2",
"vec3<u32>": "uvec3",
"vec4<u32>": "uvec4",
"mat2x2<f32>": "mat2",
"mat2x3<f32>": "mat2x3",
"mat2x4<f32>": "mat2x4",
"mat3x2<f32>": "mat3x2",
"mat3x3<f32>": "mat3",
"mat3x4<f32>": "mat3x4",
"mat4x2<f32>": "mat4x2",
"mat4x3<f32>": "mat4x3",
"mat4x4<f32>": "mat4"
};
const glsl = UNIFORM_TYPE_TO_GLSL[uniformFormat];
return glsl;
}
// dist/lib/shader-generator/wgsl/generate-wgsl.js
function generateWGSLForModule(module2, options) {
return generateWGSLUniformDeclarations(module2, options);
}
function generateWGSLUniformDeclarations(module2, options) {
const wgsl = [];
wgsl.push(`struct ${capitalize(module2.name)} {`);
for (const [uniformName, uniformFormat] of Object.entries((module2 == null ? void 0 : module2.uniformTypes) || {})) {
const wgslUniformType = uniformFormat;
wgsl.push(` ${uniformName} : ${wgslUniformType};`);
}
wgsl.push("};");
wgsl.push(`var<uniform> ${module2.name} : ${capitalize(module2.name)};`);
return wgsl.join("\n");
}
// dist/lib/shader-generator/generate-shader.js
function generateShaderForModule(module2, options) {
switch (options.shaderLanguage) {
case "glsl":
return generateGLSLForModule(module2, options);
case "wgsl":
return generateWGSLForModule(module2, options);
}
}
// dist/lib/wgsl/get-shader-layout-wgsl.js
var import_core = require("@luma.gl/core");
var import_wgsl_reflect = require("wgsl_reflect");
function getShaderLayoutFromWGSL(source) {
var _a;
const shaderLayout = { attributes: [], bindings: [] };
let parsedWGSL;
try {
parsedWGSL = parseWGSL(source);
} catch (error) {
import_core.log.error(error.message)();
return shaderLayout;
}
for (const uniform of parsedWGSL.uniforms) {
const members = [];
for (const attribute of ((_a = uniform.type) == null ? void 0 : _a.members) || []) {
members.push({
name: attribute.name,
type: getType(attribute.type)
});
}
shaderLayout.bindings.push({
type: "uniform",
name: uniform.name,
group: uniform.group,
location: uniform.binding,
// @ts-expect-error TODO - unused for now but needs fixing
members
});
}
for (const texture of parsedWGSL.textures) {
shaderLayout.bindings.push({
type: "texture",
name: texture.name,
group: texture.group,
location: texture.binding
});
}
for (const sampler of parsedWGSL.samplers) {
shaderLayout.bindings.push({
type: "sampler",
name: sampler.name,
group: sampler.group,
location: sampler.binding
});
}
const vertex = parsedWGSL.entry.vertex[0];
const attributeCount = (vertex == null ? void 0 : vertex.inputs.length) || 0;
for (let i = 0; i < attributeCount; i++) {
const wgslAttribute = vertex.inputs[i];
if (wgslAttribute.locationType === "location") {
const type = getType(wgslAttribute.type);
shaderLayout.attributes.push({
name: wgslAttribute.name,
location: Number(wgslAttribute.location),
type
});
}
}
return shaderLayout;
}
function getType(type) {
return type.format ? `${type.name}<${type.format.name}>` : type.name;
}
function parseWGSL(source) {
try {
return new import_wgsl_reflect.WgslReflect(source);
} catch (error) {
if (error instanceof Error) {
throw error;
}
let message = "WGSL parse error";
if (typeof error === "object" && (error == null ? void 0 : error.message)) {
message += `: ${error.message} `;
}
if (typeof error === "object" && (error == null ? void 0 : error.token)) {
message += error.token.line || "";
}
throw new Error(message, { cause: error });
}
}
// dist/modules/math/fp16/fp16-utils.js
var import_core2 = require("@math.gl/core");
var float16Tables = null;
var buffer = new ArrayBuffer(4);
var floatView = new Float32Array(buffer);
var uint32View = new Uint32Array(buffer);
function toHalfFloat(val) {
float16Tables ||= generateFloat16Tables();
val = (0, import_core2.clamp)(val, -65504, 65504);
floatView[0] = val;
const f = uint32View[0];
const e = f >> 23 & 511;
return float16Tables.baseTable[e] + ((f & 8388607) >> float16Tables.shiftTable[e]);
}
function fromHalfFloat(val) {
float16Tables ||= generateFloat16Tables();
const m = val >> 10;
uint32View[0] = float16Tables.mantissaTable[float16Tables.offsetTable[m] + (val & 1023)] + float16Tables.exponentTable[m];
return floatView[0];
}
function generateFloat16Tables() {
const baseTable = new Uint32Array(512);
const shiftTable = new Uint32Array(512);
for (let i = 0; i < 256; ++i) {
const e = i - 127;
if (e < -27) {
baseTable[i] = 0;
baseTable[i | 256] = 32768;
shiftTable[i] = 24;
shiftTable[i | 256] = 24;
} else if (e < -14) {
baseTable[i] = 1024 >> -e - 14;
baseTable[i | 256] = 1024 >> -e - 14 | 32768;
shiftTable[i] = -e - 1;
shiftTable[i | 256] = -e - 1;
} else if (e <= 15) {
baseTable[i] = e + 15 << 10;
baseTable[i | 256] = e + 15 << 10 | 32768;
shiftTable[i] = 13;
shiftTable[i | 256] = 13;
} else if (e < 128) {
baseTable[i] = 31744;
baseTable[i | 256] = 64512;
shiftTable[i] = 24;
shiftTable[i | 256] = 24;
} else {
baseTable[i] = 31744;
baseTable[i | 256] = 64512;
shiftTable[i] = 13;
shiftTable[i | 256] = 13;
}
}
const mantissaTable = new Uint32Array(2048);
const exponentTable = new Uint32Array(64);
const offsetTable = new Uint32Array(64);
for (let i = 1; i < 1024; ++i) {
let m = i << 13;
let e = 0;
while ((m & 8388608) === 0) {
m <<= 1;
e -= 8388608;
}
m &= ~8388608;
e += 947912704;
mantissaTable[i] = m | e;
}
for (let i = 1024; i < 2048; ++i) {
mantissaTable[i] = 939524096 + (i - 1024 << 13);
}
for (let i = 1; i < 31; ++i) {
exponentTable[i] = i << 23;
}
exponentTable[31] = 1199570944;
exponentTable[32] = 2147483648;
for (let i = 33; i < 63; ++i) {
exponentTable[i] = 2147483648 + (i - 32 << 23);
}
exponentTable[63] = 3347054592;
for (let i = 1; i < 64; ++i) {
if (i !== 32) {
offsetTable[i] = 1024;
}
}
return { baseTable, shiftTable, mantissaTable, exponentTable, offsetTable };
}
// dist/modules/math/fp64/fp64-utils.js
function fp64ify(a, out = [], startIndex = 0) {
const hiPart = Math.fround(a);
const loPart = a - hiPart;
out[startIndex] = hiPart;
out[startIndex + 1] = loPart;
return out;
}
function fp64LowPart(a) {
return a - Math.fround(a);
}
function fp64ifyMatrix4(matrix) {
const matrixFP64 = new Float32Array(32);
for (let i = 0; i < 4; ++i) {
for (let j = 0; j < 4; ++j) {
const index = i * 4 + j;
fp64ify(matrix[j * 4 + i], matrixFP64, index * 2);
}
}
return matrixFP64;
}
// dist/modules/math/random/random.js
var fs = (
/* glsl */
`float random(vec3 scale, float seed) {
/* use the fragment position for a different seed per-pixel */
return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);
}
`
);
var random = {
name: "random",
fs
};
// dist/modules/math/fp32/fp32.js
var fp32shader = (
/* glsl */
`#ifdef LUMA_FP32_TAN_PRECISION_WORKAROUND
// All these functions are for substituting tan() function from Intel GPU only
const float TWO_PI = 6.2831854820251465;
const float PI_2 = 1.5707963705062866;
const float PI_16 = 0.1963495463132858;
const float SIN_TABLE_0 = 0.19509032368659973;
const float SIN_TABLE_1 = 0.3826834261417389;
const float SIN_TABLE_2 = 0.5555702447891235;
const float SIN_TABLE_3 = 0.7071067690849304;
const float COS_TABLE_0 = 0.9807852506637573;
const float COS_TABLE_1 = 0.9238795042037964;
const float COS_TABLE_2 = 0.8314695954322815;
const float COS_TABLE_3 = 0.7071067690849304;
const float INVERSE_FACTORIAL_3 = 1.666666716337204e-01; // 1/3!
const float INVERSE_FACTORIAL_5 = 8.333333767950535e-03; // 1/5!
const float INVERSE_FACTORIAL_7 = 1.9841270113829523e-04; // 1/7!
const float INVERSE_FACTORIAL_9 = 2.75573188446287533e-06; // 1/9!
float sin_taylor_fp32(float a) {
float r, s, t, x;
if (a == 0.0) {
return 0.0;
}
x = -a * a;
s = a;
r = a;
r = r * x;
t = r * INVERSE_FACTORIAL_3;
s = s + t;
r = r * x;
t = r * INVERSE_FACTORIAL_5;
s = s + t;
r = r * x;
t = r * INVERSE_FACTORIAL_7;
s = s + t;
r = r * x;
t = r * INVERSE_FACTORIAL_9;
s = s + t;
return s;
}
void sincos_taylor_fp32(float a, out float sin_t, out float cos_t) {
if (a == 0.0) {
sin_t = 0.0;
cos_t = 1.0;
}
sin_t = sin_taylor_fp32(a);
cos_t = sqrt(1.0 - sin_t * sin_t);
}
float tan_taylor_fp32(float a) {
float sin_a;
float cos_a;
if (a == 0.0) {
return 0.0;
}
// 2pi range reduction
float z = floor(a / TWO_PI);
float r = a - TWO_PI * z;
float t;
float q = floor(r / PI_2 + 0.5);
int j = int(q);
if (j < -2 || j > 2) {
return 1.0 / 0.0;
}
t = r - PI_2 * q;
q = floor(t / PI_16 + 0.5);
int k = int(q);
int abs_k = int(abs(float(k)));
if (abs_k > 4) {
return 1.0 / 0.0;
} else {
t = t - PI_16 * q;
}
float u = 0.0;
float v = 0.0;
float sin_t, cos_t;
float s, c;
sincos_taylor_fp32(t, sin_t, cos_t);
if (k == 0) {
s = sin_t;
c = cos_t;
} else {
if (abs(float(abs_k) - 1.0) < 0.5) {
u = COS_TABLE_0;
v = SIN_TABLE_0;
} else if (abs(float(abs_k) - 2.0) < 0.5) {
u = COS_TABLE_1;
v = SIN_TABLE_1;
} else if (abs(float(abs_k) - 3.0) < 0.5) {
u = COS_TABLE_2;
v = SIN_TABLE_2;
} else if (abs(float(abs_k) - 4.0) < 0.5) {
u = COS_TABLE_3;
v = SIN_TABLE_3;
}
if (k > 0) {
s = u * sin_t + v * cos_t;
c = u * cos_t - v * sin_t;
} else {
s = u * sin_t - v * cos_t;
c = u * cos_t + v * sin_t;
}
}
if (j == 0) {
sin_a = s;
cos_a = c;
} else if (j == 1) {
sin_a = c;
cos_a = -s;
} else if (j == -1) {
sin_a = -c;
cos_a = s;
} else {
sin_a = -s;
cos_a = -c;
}
return sin_a / cos_a;
}
#endif
float tan_fp32(float a) {
#ifdef LUMA_FP32_TAN_PRECISION_WORKAROUND
return tan_taylor_fp32(a);
#else
return tan(a);
#endif
}
`
);
var fp32 = {
name: "fp32",
vs: fp32shader
};
// dist/modules/math/fp64/fp64-arithmetic-glsl.js
var fp64arithmeticShader = (
/* glsl */
`
uniform fp64arithmeticUniforms {
uniform float ONE;
} fp64;
/*
About LUMA_FP64_CODE_ELIMINATION_WORKAROUND
The purpose of this workaround is to prevent shader compilers from
optimizing away necessary arithmetic operations by swapping their sequences
or transform the equation to some 'equivalent' form.
The method is to multiply an artifical variable, ONE, which will be known to
the compiler to be 1 only at runtime. The whole expression is then represented
as a polynomial with respective to ONE. In the coefficients of all terms, only one a
and one b should appear
err = (a + b) * ONE^6 - a * ONE^5 - (a + b) * ONE^4 + a * ONE^3 - b - (a + b) * ONE^2 + a * ONE
*/
// Divide float number to high and low floats to extend fraction bits
vec2 split(float a) {
const float SPLIT = 4097.0;
float t = a * SPLIT;
#if defined(LUMA_FP64_CODE_ELIMINATION_WORKAROUND)
float a_hi = t * fp64.ONE - (t - a);
float a_lo = a * fp64.ONE - a_hi;
#else
float a_hi = t - (t - a);
float a_lo = a - a_hi;
#endif
return vec2(a_hi, a_lo);
}
// Divide float number again when high float uses too many fraction bits
vec2 split2(vec2 a) {
vec2 b = split(a.x);
b.y += a.y;
return b;
}
// Special sum operation when a > b
vec2 quickTwoSum(float a, float b) {
#if defined(LUMA_FP64_CODE_ELIMINATION_WORKAROUND)
float sum = (a + b) * fp64.ONE;
float err = b - (sum - a) * fp64.ONE;
#else
float sum = a + b;
float err = b - (sum - a);
#endif
return vec2(sum, err);
}
// General sum operation
vec2 twoSum(float a, float b) {
float s = (a + b);
#if defined(LUMA_FP64_CODE_ELIMINATION_WORKAROUND)
float v = (s * fp64.ONE - a) * fp64.ONE;
float err = (a - (s - v) * fp64.ONE) * fp64.ONE * fp64.ONE * fp64.ONE + (b - v);
#else
float v = s - a;
float err = (a - (s - v)) + (b - v);
#endif
return vec2(s, err);
}
vec2 twoSub(float a, float b) {
float s = (a - b);
#if defined(LUMA_FP64_CODE_ELIMINATION_WORKAROUND)
float v = (s * fp64.ONE - a) * fp64.ONE;
float err = (a - (s - v) * fp64.ONE) * fp64.ONE * fp64.ONE * fp64.ONE - (b + v);
#else
float v = s - a;
float err = (a - (s - v)) - (b + v);
#endif
return vec2(s, err);
}
vec2 twoSqr(float a) {
float prod = a * a;
vec2 a_fp64 = split(a);
#if defined(LUMA_FP64_CODE_ELIMINATION_WORKAROUND)
float err = ((a_fp64.x * a_fp64.x - prod) * fp64.ONE + 2.0 * a_fp64.x *
a_fp64.y * fp64.ONE * fp64.ONE) + a_fp64.y * a_fp64.y * fp64.ONE * fp64.ONE * fp64.ONE;
#else
float err = ((a_fp64.x * a_fp64.x - prod) + 2.0 * a_fp64.x * a_fp64.y) + a_fp64.y * a_fp64.y;
#endif
return vec2(prod, err);
}
vec2 twoProd(float a, float b) {
float prod = a * b;
vec2 a_fp64 = split(a);
vec2 b_fp64 = split(b);
float err = ((a_fp64.x * b_fp64.x - prod) + a_fp64.x * b_fp64.y +
a_fp64.y * b_fp64.x) + a_fp64.y * b_fp64.y;
return vec2(prod, err);
}
vec2 sum_fp64(vec2 a, vec2 b) {
vec2 s, t;
s = twoSum(a.x, b.x);
t = twoSum(a.y, b.y);
s.y += t.x;
s = quickTwoSum(s.x, s.y);
s.y += t.y;
s = quickTwoSum(s.x, s.y);
return s;
}
vec2 sub_fp64(vec2 a, vec2 b) {
vec2 s, t;
s = twoSub(a.x, b.x);
t = twoSub(a.y, b.y);
s.y += t.x;
s = quickTwoSum(s.x, s.y);
s.y += t.y;
s = quickTwoSum(s.x, s.y);
return s;
}
vec2 mul_fp64(vec2 a, vec2 b) {
vec2 prod = twoProd(a.x, b.x);
// y component is for the error
prod.y += a.x * b.y;
#if defined(LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND)
prod = split2(prod);
#endif
prod = quickTwoSum(prod.x, prod.y);
prod.y += a.y * b.x;
#if defined(LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND)
prod = split2(prod);
#endif
prod = quickTwoSum(prod.x, prod.y);
return prod;
}
vec2 div_fp64(vec2 a, vec2 b) {
float xn = 1.0 / b.x;
#if defined(LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND)
vec2 yn = mul_fp64(a, vec2(xn, 0));
#else
vec2 yn = a * xn;
#endif
float diff = (sub_fp64(a, mul_fp64(b, yn))).x;
vec2 prod = twoProd(xn, diff);
return sum_fp64(yn, prod);
}
vec2 sqrt_fp64(vec2 a) {
if (a.x == 0.0 && a.y == 0.0) return vec2(0.0, 0.0);
if (a.x < 0.0) return vec2(0.0 / 0.0, 0.0 / 0.0);
float x = 1.0 / sqrt(a.x);
float yn = a.x * x;
#if defined(LUMA_FP64_CODE_ELIMINATION_WORKAROUND)
vec2 yn_sqr = twoSqr(yn) * fp64.ONE;
#else
vec2 yn_sqr = twoSqr(yn);
#endif
float diff = sub_fp64(a, yn_sqr).x;
vec2 prod = twoProd(x * 0.5, diff);
#if defined(LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND)
return sum_fp64(split(yn), prod);
#else
return sum_fp64(vec2(yn, 0.0), prod);
#endif
}
`
);
// dist/modules/math/fp64/fp64-functions-glsl.js
var fp64functionShader = (
/* glsl */
`const vec2 E_FP64 = vec2(2.7182817459106445e+00, 8.254840366817007e-08);
const vec2 LOG2_FP64 = vec2(0.6931471824645996e+00, -1.9046542121259336e-09);
const vec2 PI_FP64 = vec2(3.1415927410125732, -8.742278012618954e-8);
const vec2 TWO_PI_FP64 = vec2(6.2831854820251465, -1.7484556025237907e-7);
const vec2 PI_2_FP64 = vec2(1.5707963705062866, -4.371139006309477e-8);
const vec2 PI_4_FP64 = vec2(0.7853981852531433, -2.1855695031547384e-8);
const vec2 PI_16_FP64 = vec2(0.19634954631328583, -5.463923757886846e-9);
const vec2 PI_16_2_FP64 = vec2(0.39269909262657166, -1.0927847515773692e-8);
const vec2 PI_16_3_FP64 = vec2(0.5890486240386963, -1.4906100798128818e-9);
const vec2 PI_180_FP64 = vec2(0.01745329238474369, 1.3519960498364902e-10);
const vec2 SIN_TABLE_0_FP64 = vec2(0.19509032368659973, -1.