|
@@ -11,6 +11,106 @@ import {
|
|
|
|
|
|
import * as fflate from '../libs/fflate.module.js';
|
|
|
|
|
|
+class USDAParser {
|
|
|
+
|
|
|
+ parse( text ) {
|
|
|
+
|
|
|
+ const data = {};
|
|
|
+
|
|
|
+ const lines = text.split( '\n' );
|
|
|
+ const length = lines.length;
|
|
|
+
|
|
|
+ let current = 0;
|
|
|
+ let string = null;
|
|
|
+ let target = data;
|
|
|
+
|
|
|
+ const stack = [ data ];
|
|
|
+
|
|
|
+ // debugger;
|
|
|
+
|
|
|
+ function parseNextLine() {
|
|
|
+
|
|
|
+ const line = lines[ current ];
|
|
|
+
|
|
|
+ // console.log( line );
|
|
|
+
|
|
|
+ if ( line.includes( '=' ) ) {
|
|
|
+
|
|
|
+ const assignment = line.split( '=' );
|
|
|
+
|
|
|
+ const lhs = assignment[ 0 ].trim();
|
|
|
+ const rhs = assignment[ 1 ].trim();
|
|
|
+
|
|
|
+ if ( rhs.endsWith( '{' ) ) {
|
|
|
+
|
|
|
+ const group = {};
|
|
|
+ stack.push( group );
|
|
|
+
|
|
|
+ target[ lhs ] = group;
|
|
|
+ target = group;
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ target[ lhs ] = rhs;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } else if ( line.endsWith( '{' ) ) {
|
|
|
+
|
|
|
+ const group = target[ string ] || {};
|
|
|
+ stack.push( group );
|
|
|
+
|
|
|
+ target[ string ] = group;
|
|
|
+ target = group;
|
|
|
+
|
|
|
+ } else if ( line.endsWith( '}' ) ) {
|
|
|
+
|
|
|
+ stack.pop();
|
|
|
+
|
|
|
+ if ( stack.length === 0 ) return;
|
|
|
+
|
|
|
+ target = stack[ stack.length - 1 ];
|
|
|
+
|
|
|
+ } else if ( line.endsWith( '(' ) ) {
|
|
|
+
|
|
|
+ const meta = {};
|
|
|
+ stack.push( meta );
|
|
|
+
|
|
|
+ string = line.split( '(' )[ 0 ].trim() || string;
|
|
|
+
|
|
|
+ target[ string ] = meta;
|
|
|
+ target = meta;
|
|
|
+
|
|
|
+ } else if ( line.endsWith( ')' ) ) {
|
|
|
+
|
|
|
+ stack.pop();
|
|
|
+
|
|
|
+ target = stack[ stack.length - 1 ];
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ string = line.trim();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ current ++;
|
|
|
+
|
|
|
+ if ( current < length ) {
|
|
|
+
|
|
|
+ parseNextLine();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ parseNextLine();
|
|
|
+
|
|
|
+ return data;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
class USDZLoader extends Loader {
|
|
|
|
|
|
constructor( manager ) {
|
|
@@ -56,7 +156,9 @@ class USDZLoader extends Loader {
|
|
|
|
|
|
parse( buffer ) {
|
|
|
|
|
|
- function createImages( zip ) {
|
|
|
+ const parser = new USDAParser();
|
|
|
+
|
|
|
+ function parseAssets( zip ) {
|
|
|
|
|
|
const data = {};
|
|
|
const loader = new FileLoader();
|
|
@@ -71,6 +173,13 @@ class USDZLoader extends Loader {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ if ( filename.endsWith( 'usd' ) ) {
|
|
|
+
|
|
|
+ const text = fflate.strFromU8( zip[ filename ] );
|
|
|
+ data[ filename ] = parser.parse( text );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
return data;
|
|
@@ -95,7 +204,10 @@ class USDZLoader extends Loader {
|
|
|
|
|
|
// console.log( zip );
|
|
|
|
|
|
- const images = createImages( zip );
|
|
|
+ const assets = parseAssets( zip );
|
|
|
+
|
|
|
+ // console.log( assets )
|
|
|
+
|
|
|
const file = findUSD( zip );
|
|
|
|
|
|
if ( file === undefined ) {
|
|
@@ -106,108 +218,51 @@ class USDZLoader extends Loader {
|
|
|
|
|
|
}
|
|
|
|
|
|
+
|
|
|
// Parse file
|
|
|
|
|
|
const text = fflate.strFromU8( file );
|
|
|
- const lines = text.split( '\n' );
|
|
|
- const length = lines.length;
|
|
|
-
|
|
|
- const data = {};
|
|
|
+ const data = parser.parse( text );
|
|
|
|
|
|
- let current = 0;
|
|
|
- let string = null;
|
|
|
- let target = data;
|
|
|
-
|
|
|
- const stack = [ data ];
|
|
|
-
|
|
|
- // debugger;
|
|
|
-
|
|
|
- function parseNextLine() {
|
|
|
+ // Build scene
|
|
|
|
|
|
- const line = lines[ current ];
|
|
|
+ function findGeometry( data, id ) {
|
|
|
|
|
|
- // console.log( line );
|
|
|
+ if ( 'prepend references' in data ) {
|
|
|
|
|
|
- if ( line.includes( '=' ) ) {
|
|
|
+ const reference = data[ 'prepend references' ];
|
|
|
+ const parts = reference.split( '@' );
|
|
|
+ const path = parts[ 1 ].replace( /^.\//, '' );
|
|
|
+ const id = parts[ 2 ].replace( /^<\//, '' ).replace( />$/, '' );
|
|
|
+ return findGeometry( assets[ path ], id );
|
|
|
|
|
|
- const assignment = line.split( '=' );
|
|
|
-
|
|
|
- const lhs = assignment[ 0 ].trim();
|
|
|
- const rhs = assignment[ 1 ].trim();
|
|
|
-
|
|
|
- if ( rhs.endsWith( '{' ) ) {
|
|
|
+ }
|
|
|
|
|
|
- const group = {};
|
|
|
- stack.push( group );
|
|
|
+ if ( id !== undefined ) {
|
|
|
|
|
|
- target[ lhs ] = group;
|
|
|
- target = group;
|
|
|
+ const def = `def "%{id}"`;
|
|
|
|
|
|
- } else {
|
|
|
+ if ( def in data ) {
|
|
|
|
|
|
- target[ lhs ] = rhs;
|
|
|
+ return data[ def ];
|
|
|
|
|
|
}
|
|
|
|
|
|
- } else if ( line.endsWith( '{' ) ) {
|
|
|
-
|
|
|
- const group = target[ string ] || {};
|
|
|
- stack.push( group );
|
|
|
-
|
|
|
- target[ string ] = group;
|
|
|
- target = group;
|
|
|
-
|
|
|
- } else if ( line.endsWith( '}' ) ) {
|
|
|
-
|
|
|
- stack.pop();
|
|
|
-
|
|
|
- if ( stack.length === 0 ) return;
|
|
|
-
|
|
|
- target = stack[ stack.length - 1 ];
|
|
|
-
|
|
|
- } else if ( line.endsWith( '(' ) ) {
|
|
|
-
|
|
|
- const meta = {};
|
|
|
- stack.push( meta );
|
|
|
-
|
|
|
- string = line.split( '(' )[ 0 ].trim() || string;
|
|
|
-
|
|
|
- target[ string ] = meta;
|
|
|
- target = meta;
|
|
|
-
|
|
|
- } else if ( line.endsWith( ')' ) ) {
|
|
|
-
|
|
|
- stack.pop();
|
|
|
-
|
|
|
- target = stack[ stack.length - 1 ];
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- string = line.trim();
|
|
|
-
|
|
|
}
|
|
|
|
|
|
- current ++;
|
|
|
-
|
|
|
- if ( current < length ) {
|
|
|
-
|
|
|
- parseNextLine();
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
+ for ( const name in data ) {
|
|
|
|
|
|
- parseNextLine();
|
|
|
+ const object = data[ name ];
|
|
|
|
|
|
- // Build scene
|
|
|
+ if ( name.startsWith( 'def Mesh' ) ) {
|
|
|
|
|
|
- function findGeometry( data ) {
|
|
|
+ // Move points to Mesh
|
|
|
|
|
|
- for ( const name in data ) {
|
|
|
+ if ( data[ 'point3f[] points' ] ) {
|
|
|
|
|
|
- const object = data[ name ];
|
|
|
+ object[ 'point3f[] points' ] = data[ 'point3f[] points' ];
|
|
|
|
|
|
- if ( name.startsWith( 'def Mesh' ) ) {
|
|
|
+ }
|
|
|
|
|
|
// Move st indices to Mesh
|
|
|
|
|
@@ -241,7 +296,7 @@ class USDZLoader extends Loader {
|
|
|
const positions = JSON.parse( data[ 'point3f[] points' ].replace( /[()]*/g, '' ) );
|
|
|
const attribute = new BufferAttribute( new Float32Array( positions ), 3 );
|
|
|
|
|
|
- if ( data[ 'int[] faceVertexIndices' ] ) {
|
|
|
+ if ( 'int[] faceVertexIndices' in data ) {
|
|
|
|
|
|
const indices = JSON.parse( data[ 'int[] faceVertexIndices' ] );
|
|
|
geometry.setAttribute( 'position', toFlatBufferAttribute( attribute, indices ) );
|
|
@@ -252,13 +307,12 @@ class USDZLoader extends Loader {
|
|
|
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- if ( data[ 'texCoord2f[] primvars:st' ] ) {
|
|
|
+ if ( 'texCoord2f[] primvars:st' in data ) {
|
|
|
|
|
|
const uvs = JSON.parse( data[ 'texCoord2f[] primvars:st' ].replace( /[()]*/g, '' ) );
|
|
|
const attribute = new BufferAttribute( new Float32Array( uvs ), 2 );
|
|
|
|
|
|
- if ( data[ 'int[] primvars:st:indices' ] ) {
|
|
|
+ if ( 'int[] primvars:st:indices' in data ) {
|
|
|
|
|
|
const indices = JSON.parse( data[ 'int[] primvars:st:indices' ] );
|
|
|
geometry.setAttribute( 'uv', toFlatBufferAttribute( attribute, indices ) );
|
|
@@ -331,26 +385,27 @@ class USDZLoader extends Loader {
|
|
|
|
|
|
const material = new MeshStandardMaterial();
|
|
|
|
|
|
- // console.log( data );
|
|
|
+ if ( data !== undefined ) {
|
|
|
|
|
|
- if ( data[ 'def Shader "diffuseColor_texture"' ] ) {
|
|
|
+ if ( 'def Shader "diffuseColor_texture"' in data ) {
|
|
|
|
|
|
- const texture = data[ 'def Shader "diffuseColor_texture"' ];
|
|
|
- const file = texture[ 'asset inputs:file' ].replace( /@*/g, '' );
|
|
|
+ const texture = data[ 'def Shader "diffuseColor_texture"' ];
|
|
|
+ const file = texture[ 'asset inputs:file' ].replace( /@*/g, '' );
|
|
|
|
|
|
- material.map = new TextureLoader().load( images[ file ] );
|
|
|
+ material.map = new TextureLoader().load( assets[ file ] );
|
|
|
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- if ( data[ 'def Shader "normal_texture"' ] ) {
|
|
|
+ if ( 'def Shader "normal_texture"' in data ) {
|
|
|
|
|
|
- const texture = data[ 'def Shader "normal_texture"' ];
|
|
|
- const file = texture[ 'asset inputs:file' ].replace( /@*/g, '' );
|
|
|
+ const texture = data[ 'def Shader "normal_texture"' ];
|
|
|
+ const file = texture[ 'asset inputs:file' ].replace( /@*/g, '' );
|
|
|
|
|
|
- material.normalMap = new TextureLoader().load( images[ file ] );
|
|
|
+ material.normalMap = new TextureLoader().load( assets[ file ] );
|
|
|
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
+ }
|
|
|
|
|
|
return material;
|
|
|
|