@giro3d/giro3d
Version:
A JS/WebGL framework for 3D geospatial data visualization
136 lines (121 loc) • 3.85 kB
text/typescript
/*
* Copyright (c) 2015-2018, IGN France.
* Copyright (c) 2018-2026, Giro3D team.
* SPDX-License-Identifier: MIT
*/
import type { BufferAttribute } from 'three';
import {
Float16BufferAttribute,
Float32BufferAttribute,
Int16BufferAttribute,
Int32BufferAttribute,
Int8BufferAttribute,
Uint16BufferAttribute,
Uint32BufferAttribute,
Uint8BufferAttribute,
Uint8ClampedBufferAttribute,
} from 'three';
export interface HasDefines {
defines: Record<string, unknown>;
needsUpdate: boolean;
}
/**
* Sets or unsets a define directive according to the condition.
* The material is updated only if the directive has changed, avoiding unnecessary recompilations.
*
* @param material - The material to update.
* @param name - The name of the directive
* @param condition - The condition to enable the directive.
* @example
*
* setDefine(mat, 'ENABLE_FOO', true); // material.needsUpdate === true;
* setDefine(mat, 'ENABLE_FOO', true); // material.needsUpdate === false;
* setDefine(mat, 'ENABLE_FOO', false); // material.needsUpdate === true;
*/
function setDefine<M extends HasDefines, K extends keyof M['defines']>(
material: M,
name: K,
condition: boolean | undefined | null,
): void {
condition = condition ?? false;
if (material.defines == null) {
throw new Error('material.defines is null');
}
const key = name as string;
if (material.defines[key] === undefined) {
if (condition) {
material.defines[key] = 1;
material.needsUpdate = true;
}
} else if (!condition) {
delete material.defines[key];
material.needsUpdate = true;
}
}
/**
* Sets or unsets a valued define directive.
* The material is updated only if the value has changed, avoiding unnecessary recompilations.
*
* @param material - The material to update.
* @param name - The name of the directive
* @param value - The value of the define.
* @returns `true` if the define value has actually changed, `false` otherwise.
* @example
*
* setValueDefine(mat, 'FOO_COUNT', 5); // material.needsUpdate === true;
* setValueDefine(mat, 'FOO_COUNT', 5); // material.needsUpdate === false;
* setValueDefine(mat, 'FOO_COUNT', 4); // material.needsUpdate === true;
*/
function setDefineValue<M extends HasDefines, K extends keyof M['defines']>(
material: M,
name: K,
value?: number | string,
): boolean {
if (material.defines == null) {
throw new Error('material.defines is null');
}
const key = name as string;
const changed = material.defines[key] !== value;
if (value != null) {
material.defines[key] = value;
} else {
delete material.defines[key];
}
if (changed) {
material.needsUpdate = true;
}
return changed;
}
export type VertexAttributeType = 'int' | 'uint' | 'float';
/**
* Returns the GLSL attribute type that most closely matches the type of the {@link BufferAttribute}.
*/
function getVertexAttributeType(attribute: BufferAttribute): VertexAttributeType {
if (
attribute instanceof Float32BufferAttribute ||
attribute instanceof Float16BufferAttribute
) {
return 'float';
}
if (
attribute instanceof Int32BufferAttribute ||
attribute instanceof Int16BufferAttribute ||
attribute instanceof Int8BufferAttribute
) {
return 'int';
}
if (
attribute instanceof Uint32BufferAttribute ||
attribute instanceof Uint16BufferAttribute ||
attribute instanceof Uint8BufferAttribute ||
attribute instanceof Uint8ClampedBufferAttribute
) {
return 'uint';
}
throw new Error('unsupported vertex attribute type');
}
export default {
setDefine,
setDefineValue,
getVertexAttributeType,
};