Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,107 changes: 68 additions & 1,039 deletions examples/jsm/loaders/MaterialXLoader.js

Large diffs are not rendered by default.

108 changes: 108 additions & 0 deletions examples/jsm/loaders/materialx/MaterialXArchive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { unzipSync } from '../../libs/fflate.module.js';

const _textDecoder = new TextDecoder();

function normalizePath( path ) {

return path
.split( '\\' ).join( '/' )
.replace( /^\.?\//, '' )
.replace( /^\/+/, '' );

}

function isZipBuffer( buffer ) {

const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array( buffer );
return bytes.length >= 4 && bytes[ 0 ] === 0x50 && bytes[ 1 ] === 0x4b;

}

function readMtlxArchive( buffer ) {

const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array( buffer );
const archive = unzipSync( bytes );

const fileMap = new Map();
let mtlxPath = null;

for ( const path in archive ) {

const normalizedPath = normalizePath( path );
fileMap.set( normalizedPath, archive[ path ] );

if ( normalizedPath.toLowerCase().endsWith( '.mtlx' ) ) {

if ( mtlxPath !== null ) {

throw new Error( 'THREE.MaterialXLoader: Invalid .mtlx.zip package. Exactly one .mtlx file is required.' );

}

mtlxPath = normalizedPath;

}

}

if ( mtlxPath === null ) {

throw new Error( 'THREE.MaterialXLoader: Invalid .mtlx.zip package. Missing .mtlx file.' );

}

const text = _textDecoder.decode( fileMap.get( mtlxPath ) );
return { text, mtlxPath, files: fileMap };

}

function createArchiveResolver( files ) {

const objectUrlCache = new Map();

const getFile = ( uri ) => {

const normalized = normalizePath( decodeURI( uri ) );
if ( files.has( normalized ) ) return files.get( normalized );

for ( const [ path, bytes ] of files ) {

if ( path.endsWith( normalized ) ) return bytes;

}

return null;

};

const resolve = ( uri ) => {

if ( objectUrlCache.has( uri ) ) return objectUrlCache.get( uri );

const bytes = getFile( uri );
if ( ! bytes ) return null;

const blob = new Blob( [ bytes ], { type: 'application/octet-stream' } );
const objectUrl = URL.createObjectURL( blob );
objectUrlCache.set( uri, objectUrl );
return objectUrl;

};

const dispose = () => {

for ( const objectUrl of objectUrlCache.values() ) {

URL.revokeObjectURL( objectUrl );

}

objectUrlCache.clear();

};

return { resolve, dispose };

}

export { isZipBuffer, readMtlxArchive, createArchiveResolver };
Loading
Loading