@pmndrs/uikit
Version:
Build performant 3D user interfaces with Three.js and yoga.
127 lines (126 loc) • 4.32 kB
JavaScript
import { computed } from '@preact/signals-core';
import { computedInheritableProperty } from './properties/index.js';
import { readReactive } from './utils.js';
export const reversePainterSortStableCacheKey = Symbol('reverse-painter-sort-stable-cache-key');
export const orderInfoKey = Symbol('order-info-key');
export function reversePainterSortStable(a, b) {
if (a.groupOrder !== b.groupOrder) {
return a.groupOrder - b.groupOrder;
}
if (a.renderOrder !== b.renderOrder) {
return a.renderOrder - b.renderOrder;
}
let az = a.z;
let bz = b.z;
const aDistanceRef = a.object[reversePainterSortStableCacheKey];
const bDistanceRef = b.object[reversePainterSortStableCacheKey];
if (aDistanceRef != null) {
aDistanceRef.reversePainterSortStableCache ??= az;
az = aDistanceRef.reversePainterSortStableCache;
}
if (bDistanceRef != null) {
bDistanceRef.reversePainterSortStableCache ??= bz;
bz = bDistanceRef.reversePainterSortStableCache;
}
if (aDistanceRef != null && aDistanceRef === bDistanceRef) {
return compareOrderInfo(a.object[orderInfoKey].value, b.object[orderInfoKey].value);
}
//default z comparison
return az !== bz ? bz - az : a.id - b.id;
}
//the following order tries to represent the most common element order of the respective element types (e.g. panels are most likely the background element)
export const ElementType = {
Panel: 0, //render first
Image: 1,
Object: 2,
Custom: 3,
Svg: 4,
Text: 5, //render last
};
export function compareOrderInfo(o1, o2) {
if (o1 == null || o2 == null) {
return 0;
}
let dif = o1.majorIndex - o2.majorIndex;
if (dif != 0) {
return dif;
}
dif = o1.elementType - o2.elementType;
if (dif != 0) {
return dif;
}
return o1.minorIndex - o2.minorIndex;
}
export function computedOrderInfo(propertiesSignal, zIndexOffsetKey, type, instancedGroupDependencies, parentOrderInfoSignal) {
const zIndexOffset = propertiesSignal == null
? undefined
: computedInheritableProperty(propertiesSignal, zIndexOffsetKey, undefined);
return computed(() => {
let parentOrderInfo;
if (parentOrderInfoSignal == null) {
parentOrderInfo = undefined;
}
else if (parentOrderInfoSignal.value == null) {
return undefined;
}
else {
parentOrderInfo = parentOrderInfoSignal.value;
}
const offset = zIndexOffset?.value;
const majorOffset = typeof offset === 'number' ? offset : (offset?.major ?? 0);
const minorOffset = typeof offset === 'number' ? 0 : (offset?.minor ?? 0);
let majorIndex;
let minorIndex;
if (parentOrderInfo == null) {
majorIndex = 0;
minorIndex = 0;
}
else if (type > parentOrderInfo.elementType) {
majorIndex = parentOrderInfo.majorIndex;
minorIndex = 0;
}
else if (type != parentOrderInfo.elementType ||
!shallowEqualRecord(readReactive(instancedGroupDependencies), readReactive(parentOrderInfo.instancedGroupDependencies))) {
majorIndex = parentOrderInfo.majorIndex + 1;
minorIndex = 0;
}
else {
majorIndex = parentOrderInfo.majorIndex;
minorIndex = parentOrderInfo.minorIndex + 1;
}
if (majorOffset > 0) {
majorIndex += majorOffset;
minorIndex = 0;
}
minorIndex += minorOffset;
return {
instancedGroupDependencies,
elementType: type,
majorIndex,
minorIndex,
};
});
}
function shallowEqualRecord(r1, r2) {
if (r1 === r2) {
return true;
}
if (r1 == null || r2 == null) {
return false;
}
//i counts the number of keys in r1
let i = 0;
for (const key in r1) {
if (r1[key] != r2[key]) {
return false;
}
++i;
}
return i === Object.keys(r2).length;
}
export function setupRenderOrder(result, rootCameraDistance, orderInfo) {
;
result[reversePainterSortStableCacheKey] = rootCameraDistance;
result[orderInfoKey] = orderInfo;
return result;
}