@luma.gl/core
Version:
The luma.gl core Device API
144 lines • 6.28 kB
JavaScript
// luma.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
import { log } from "../utils/log.js";
import { shaderTypeDecoder } from "../shadertypes/shader-types/shader-type-decoder.js";
import { vertexFormatDecoder } from "../shadertypes/vertex-types/vertex-format-decoder.js";
/**
* Map from "attribute names" to "resolved attribute infos"
* containing information about both buffer layouts and shader attribute declarations
*/
export function getAttributeInfosFromLayouts(shaderLayout, bufferLayout) {
const attributeInfos = {};
for (const attribute of shaderLayout.attributes) {
const attributeInfo = getAttributeInfoFromLayouts(shaderLayout, bufferLayout, attribute.name);
if (attributeInfo) {
attributeInfos[attribute.name] = attributeInfo;
}
}
return attributeInfos;
}
/**
* Array indexed by "location" holding "resolved attribute infos"
*/
export function getAttributeInfosByLocation(shaderLayout, bufferLayout, maxVertexAttributes = 16) {
const attributeInfos = getAttributeInfosFromLayouts(shaderLayout, bufferLayout);
const locationInfos = new Array(maxVertexAttributes).fill(null);
for (const attributeInfo of Object.values(attributeInfos)) {
locationInfos[attributeInfo.location] = attributeInfo;
}
return locationInfos;
}
/**
* Get the combined information from a shader layout and a buffer layout for a specific attribute
*/
function getAttributeInfoFromLayouts(shaderLayout, bufferLayout, name) {
const shaderDeclaration = getAttributeFromShaderLayout(shaderLayout, name);
const bufferMapping = getAttributeFromBufferLayout(bufferLayout, name);
// TODO should no longer happen
if (!shaderDeclaration) {
// || !bufferMapping
return null;
}
const attributeTypeInfo = shaderTypeDecoder.getAttributeShaderTypeInfo(shaderDeclaration.type);
const defaultVertexFormat = vertexFormatDecoder.getCompatibleVertexFormat(attributeTypeInfo);
const vertexFormat = bufferMapping?.vertexFormat || defaultVertexFormat;
const vertexFormatInfo = vertexFormatDecoder.getVertexFormatInfo(vertexFormat);
return {
attributeName: bufferMapping?.attributeName || shaderDeclaration.name,
bufferName: bufferMapping?.bufferName || shaderDeclaration.name,
location: shaderDeclaration.location,
shaderType: shaderDeclaration.type,
primitiveType: attributeTypeInfo.primitiveType,
shaderComponents: attributeTypeInfo.components,
vertexFormat,
bufferDataType: vertexFormatInfo.type,
bufferComponents: vertexFormatInfo.components,
// normalized is a property of the buffer's vertex format
normalized: vertexFormatInfo.normalized,
// integer is a property of the shader declaration
integer: attributeTypeInfo.integer,
stepMode: bufferMapping?.stepMode || shaderDeclaration.stepMode || 'vertex',
byteOffset: bufferMapping?.byteOffset || 0,
byteStride: bufferMapping?.byteStride || 0
};
}
function getAttributeFromShaderLayout(shaderLayout, name) {
const attribute = shaderLayout.attributes.find(attr => attr.name === name);
if (!attribute) {
log.warn(`shader layout attribute "${name}" not present in shader`);
}
return attribute || null;
}
function getAttributeFromBufferLayout(bufferLayouts, name) {
// Check that bufferLayouts are valid (each either has format or attribute)
checkBufferLayouts(bufferLayouts);
let bufferLayoutInfo = getAttributeFromShortHand(bufferLayouts, name);
if (bufferLayoutInfo) {
return bufferLayoutInfo;
}
bufferLayoutInfo = getAttributeFromAttributesList(bufferLayouts, name);
if (bufferLayoutInfo) {
return bufferLayoutInfo;
}
// Didn't find...
log.warn(`layout for attribute "${name}" not present in buffer layout`);
return null;
}
/** Check that bufferLayouts are valid (each either has format or attribute) */
function checkBufferLayouts(bufferLayouts) {
for (const bufferLayout of bufferLayouts) {
if ((bufferLayout.attributes && bufferLayout.format) ||
(!bufferLayout.attributes && !bufferLayout.format)) {
log.warn(`BufferLayout ${name} must have either 'attributes' or 'format' field`);
}
}
}
/** Get attribute from format shorthand if specified */
function getAttributeFromShortHand(bufferLayouts, name) {
for (const bufferLayout of bufferLayouts) {
if (bufferLayout.format && bufferLayout.name === name) {
return {
attributeName: bufferLayout.name,
bufferName: name,
stepMode: bufferLayout.stepMode,
vertexFormat: bufferLayout.format,
// If offset is needed, use `attributes` field.
byteOffset: 0,
byteStride: bufferLayout.byteStride || 0
};
}
}
return null;
}
/**
* Search attribute mappings (e.g. interleaved attributes) for buffer mapping.
* Not the name of the buffer might be the same as one of the interleaved attributes.
*/
function getAttributeFromAttributesList(bufferLayouts, name) {
for (const bufferLayout of bufferLayouts) {
let byteStride = bufferLayout.byteStride;
// Calculate a default byte stride if not provided
if (typeof bufferLayout.byteStride !== 'number') {
for (const attributeMapping of bufferLayout.attributes || []) {
const info = vertexFormatDecoder.getVertexFormatInfo(attributeMapping.format);
// @ts-ignore
byteStride += info.byteLength;
}
}
const attributeMapping = bufferLayout.attributes?.find(mapping => mapping.attribute === name);
if (attributeMapping) {
return {
attributeName: attributeMapping.attribute,
bufferName: bufferLayout.name,
stepMode: bufferLayout.stepMode,
vertexFormat: attributeMapping.format,
byteOffset: attributeMapping.byteOffset,
// @ts-ignore
byteStride
};
}
}
return null;
}
//# sourceMappingURL=get-attribute-from-layouts.js.map