UNPKG

@giro3d/giro3d

Version:

A JS/WebGL framework for 3D geospatial data visualization

101 lines (84 loc) 2.45 kB
/* * Copyright (c) 2015-2018, IGN France. * Copyright (c) 2018-2026, Giro3D team. * SPDX-License-Identifier: MIT */ import { type Vector2 } from 'three'; import fit, { type Block, type Node } from './Packer'; /** * An atlas image. */ export interface AtlasImage { id: string; size: Vector2; } export interface LayerAtlasInfo { x: number; y: number; fit?: Node; offset?: number; } export type Atlas = Record<string, Node>; export interface AtlasInfo { maxX: number; maxY: number; atlas: Atlas | null; } interface LayerBlock { layerId: string; fit?: Node; w: number; h: number; } /** * Build a texture atlas from N images. * * @param maxSize - The maximum texture size of the atlas, in pixels. * @param images - The images to pack. * @param oldAtlas - The previous atlas. */ function pack(maxSize: number, images: Array<AtlasImage>, oldAtlas: Atlas | null): AtlasInfo { const blocks: LayerBlock[] = []; for (let i = 0; i < images.length; i++) { if (oldAtlas && images[i].id in oldAtlas) { continue; } const sWidth = images[i].size.width; const sHeight = images[i].size.height; blocks.push({ layerId: images[i].id, w: Math.min(maxSize, sWidth), h: Math.min(maxSize, sHeight), }); } // sort from big > small images (the packing alg works best if big images are treated first) // @ts-expect-error (we ignore the typing error of casting booleans to numbers to maintain speed) blocks.sort((a, b) => Math.max(a.w, a.h) < Math.max(b.w, b.h)); let previousRoot: Node | null = null; if (oldAtlas) { for (const k of Object.keys(oldAtlas)) { const fitResult = oldAtlas[k]; if (fitResult.x === 0 && fitResult.y === 0) { // Updating previousRoot = fitResult; break; } } } if (oldAtlas && !previousRoot) { throw new Error('oldAtlas is defined, but not previousRoot'); } const { maxX, maxY } = fit(blocks as Block[], maxSize, maxSize, previousRoot); const atlas = oldAtlas || {}; for (let i = 0; i < blocks.length; i++) { // @ts-expect-error invalid atlas[blocks[i].layerId] = { ...blocks[i].fit, offset: 0, }; } return { atlas, maxX, maxY }; } export default { pack, };