@loaders.gl/gltf
Version:
Framework-independent loader for the glTF format
99 lines (81 loc) • 3.11 kB
text/typescript
// GLTF EXTENSION: KHR_techniques_webgl
// https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_techniques_webgl
import type {GLTF} from '../../types/gltf-json-schema';
import {GLTFScenegraph} from '../../api/gltf-scenegraph';
const KHR_TECHNIQUES_WEBGL = 'KHR_techniques_webgl';
export const name = KHR_TECHNIQUES_WEBGL;
export async function decode(gltfData: {json: GLTF}): Promise<void> {
const gltfScenegraph = new GLTFScenegraph(gltfData);
const {json} = gltfScenegraph;
const extension = gltfScenegraph.getExtension(KHR_TECHNIQUES_WEBGL);
if (extension) {
const techniques = resolveTechniques(extension, gltfScenegraph);
for (const material of json.materials || []) {
const materialExtension = gltfScenegraph.getObjectExtension(material, KHR_TECHNIQUES_WEBGL);
if (materialExtension) {
// @ts-ignore TODO
material.technique = Object.assign(
{},
materialExtension,
// @ts-ignore
techniques[materialExtension.technique]
);
// @ts-ignore TODO
material.technique.values = resolveValues(material.technique, gltfScenegraph);
}
gltfScenegraph.removeObjectExtension(material, KHR_TECHNIQUES_WEBGL);
}
// Remove the top-level extension
gltfScenegraph.removeExtension(KHR_TECHNIQUES_WEBGL);
}
}
// eslint-disable-next-line
export async function encode(gltfData, options): Promise<void> {
// TODO
}
function resolveTechniques(
techniquesExtension: {[key: string]: any},
// programs: {[key: string]: any}[],
// shaders: {[key: string]: any}[],
// techniques: {[key: string]: any}[]
gltfScenegraph
) {
const {programs = [], shaders = [], techniques = []} = techniquesExtension;
const textDecoder = new TextDecoder();
shaders.forEach((shader) => {
if (Number.isFinite(shader.bufferView)) {
shader.code = textDecoder.decode(
gltfScenegraph.getTypedArrayForBufferView(shader.bufferView)
);
} else {
// TODO: handle URI shader
throw new Error('KHR_techniques_webgl: no shader code');
}
});
programs.forEach((program) => {
program.fragmentShader = shaders[program.fragmentShader];
program.vertexShader = shaders[program.vertexShader];
});
techniques.forEach((technique) => {
technique.program = programs[technique.program];
});
return techniques;
}
function resolveValues(technique, gltfScenegraph) {
const values = Object.assign({}, technique.values);
// merge values from uniforms
Object.keys(technique.uniforms || {}).forEach((uniform) => {
if (technique.uniforms[uniform].value && !(uniform in values)) {
values[uniform] = technique.uniforms[uniform].value;
}
});
// resolve textures
Object.keys(values).forEach((uniform) => {
if (typeof values[uniform] === 'object' && values[uniform].index !== undefined) {
// Assume this is a texture
// TODO: find if there are any other types that can be referenced
values[uniform].texture = gltfScenegraph.getTexture(values[uniform].index);
}
});
return values;
}