2017-03-13 15:28:51 -04:00
'use strict' ;
2019-02-05 20:59:09 -05:00
const Cesium = require ( 'cesium' ) ;
2019-10-26 20:42:12 -04:00
const path = require ( 'path' ) ;
2019-02-05 20:59:09 -05:00
const loadObj = require ( '../../lib/loadObj' ) ;
const obj2gltf = require ( '../../lib/obj2gltf' ) ;
const Cartesian3 = Cesium . Cartesian3 ;
const CesiumMath = Cesium . Math ;
const clone = Cesium . clone ;
const RuntimeError = Cesium . RuntimeError ;
const objPath = 'specs/data/box/box.obj' ;
2019-08-19 16:33:12 -07:00
const objRotatedUrl = 'specs/data/box-rotated/box-rotated.obj' ;
2019-02-05 20:59:09 -05:00
const objNormalsPath = 'specs/data/box-normals/box-normals.obj' ;
const objUvsPath = 'specs/data/box-uvs/box-uvs.obj' ;
const objPositionsOnlyPath = 'specs/data/box-positions-only/box-positions-only.obj' ;
const objNegativeIndicesPath = 'specs/data/box-negative-indices/box-negative-indices.obj' ;
const objTrianglesPath = 'specs/data/box-triangles/box-triangles.obj' ;
const objObjectsPath = 'specs/data/box-objects/box-objects.obj' ;
const objGroupsPath = 'specs/data/box-groups/box-groups.obj' ;
const objObjectsGroupsPath = 'specs/data/box-objects-groups/box-objects-groups.obj' ;
const objObjectsGroupsMaterialsPath = 'specs/data/box-objects-groups-materials/box-objects-groups-materials.obj' ;
const objObjectsGroupsMaterialsPath2 = 'specs/data/box-objects-groups-materials-2/box-objects-groups-materials-2.obj' ;
const objUsemtlPath = 'specs/data/box-usemtl/box-usemtl.obj' ;
const objNoMaterialsPath = 'specs/data/box-no-materials/box-no-materials.obj' ;
const objMultipleMaterialsPath = 'specs/data/box-multiple-materials/box-multiple-materials.obj' ;
const objUncleanedPath = 'specs/data/box-uncleaned/box-uncleaned.obj' ;
const objMtllibPath = 'specs/data/box-mtllib/box-mtllib.obj' ;
const objMtllibSpacesPath = 'specs/data/box-mtllib-spaces/box mtllib.obj' ;
const objMissingMtllibPath = 'specs/data/box-missing-mtllib/box-missing-mtllib.obj' ;
const objMissingUsemtlPath = 'specs/data/box-missing-usemtl/box-missing-usemtl.obj' ;
2019-02-10 09:45:46 -05:00
const objUnnamedMaterialPath = 'specs/data/box-unnamed-material/box-unnamed-material.obj' ;
2019-02-05 20:59:09 -05:00
const objExternalResourcesPath = 'specs/data/box-external-resources/box-external-resources.obj' ;
const objResourcesInRootPath = 'specs/data/box-resources-in-root/box-resources-in-root.obj' ;
const objExternalResourcesInRootPath = 'specs/data/box-external-resources-in-root/box-external-resources-in-root.obj' ;
const objTexturedPath = 'specs/data/box-textured/box-textured.obj' ;
const objMissingTexturePath = 'specs/data/box-missing-texture/box-missing-texture.obj' ;
const objSubdirectoriesPath = 'specs/data/box-subdirectories/box-textured.obj' ;
const objWindowsPaths = 'specs/data/box-windows-paths/box-windows-paths.obj' ;
const objInvalidContentsPath = 'specs/data/box/box.mtl' ;
const objConcavePath = 'specs/data/concave/concave.obj' ;
const objUnnormalizedPath = 'specs/data/box-unnormalized/box-unnormalized.obj' ;
const objMixedAttributesPath = 'specs/data/box-mixed-attributes/box-mixed-attributes.obj' ;
2019-10-26 20:15:10 -04:00
const objMissingAttributesPath = 'specs/data/box-missing-attributes/box-missing-attributes.obj' ;
2019-10-27 15:26:40 -04:00
const objIncompletePositionsPath = 'specs/data/box-incomplete-attributes/box-incomplete-positions.obj' ;
const objIncompleteNormalsPath = 'specs/data/box-incomplete-attributes/box-incomplete-normals.obj' ;
const objIncompleteUvsPath = 'specs/data/box-incomplete-attributes/box-incomplete-uvs.obj' ;
2019-02-05 20:59:09 -05:00
const objInvalidPath = 'invalid.obj' ;
2017-03-13 15:28:51 -04:00
function getMeshes ( data ) {
2019-02-05 20:59:09 -05:00
let meshes = [ ] ;
const nodes = data . nodes ;
const nodesLength = nodes . length ;
for ( let i = 0 ; i < nodesLength ; ++ i ) {
2017-03-13 15:28:51 -04:00
meshes = meshes . concat ( nodes [ i ] . meshes ) ;
}
return meshes ;
}
function getPrimitives ( data ) {
2019-02-05 20:59:09 -05:00
let primitives = [ ] ;
const nodes = data . nodes ;
const nodesLength = nodes . length ;
for ( let i = 0 ; i < nodesLength ; ++ i ) {
const meshes = nodes [ i ] . meshes ;
const meshesLength = meshes . length ;
for ( let j = 0 ; j < meshesLength ; ++ j ) {
2017-03-13 15:28:51 -04:00
primitives = primitives . concat ( meshes [ j ] . primitives ) ;
}
}
return primitives ;
}
2019-02-05 20:59:09 -05:00
let options ;
2017-04-10 17:57:56 -04:00
2019-02-05 20:59:09 -05:00
describe ( 'loadObj' , ( ) => {
beforeEach ( ( ) => {
2017-07-29 13:23:33 -04:00
options = clone ( obj2gltf . defaults ) ;
options . overridingTextures = { } ;
2019-02-05 20:59:09 -05:00
options . logger = ( ) => { } ;
} ) ;
it ( 'loads obj with positions, normals, and uvs' , async ( ) => {
const data = await loadObj ( objPath , options ) ;
const materials = data . materials ;
const nodes = data . nodes ;
const name = data . name ;
const meshes = getMeshes ( data ) ;
const primitives = getPrimitives ( data ) ;
expect ( name ) . toBe ( 'box' ) ;
expect ( materials . length ) . toBe ( 1 ) ;
expect ( nodes . length ) . toBe ( 1 ) ;
expect ( meshes . length ) . toBe ( 1 ) ;
expect ( primitives . length ) . toBe ( 1 ) ;
const node = nodes [ 0 ] ;
const mesh = meshes [ 0 ] ;
const primitive = primitives [ 0 ] ;
expect ( node . name ) . toBe ( 'Cube' ) ;
expect ( mesh . name ) . toBe ( 'Cube-Mesh' ) ;
expect ( primitive . positions . length / 3 ) . toBe ( 24 ) ;
expect ( primitive . normals . length / 3 ) . toBe ( 24 ) ;
expect ( primitive . uvs . length / 2 ) . toBe ( 24 ) ;
expect ( primitive . indices . length ) . toBe ( 36 ) ;
expect ( primitive . material ) . toBe ( 'Material' ) ;
} ) ;
it ( 'loads obj with normals' , async ( ) => {
const data = await loadObj ( objNormalsPath , options ) ;
const primitive = getPrimitives ( data ) [ 0 ] ;
expect ( primitive . positions . length / 3 ) . toBe ( 24 ) ;
expect ( primitive . normals . length / 3 ) . toBe ( 24 ) ;
expect ( primitive . uvs . length / 2 ) . toBe ( 0 ) ;
} ) ;
it ( 'normalizes normals' , async ( ) => {
const data = await loadObj ( objUnnormalizedPath , options ) ;
const scratchNormal = new Cesium . Cartesian3 ( ) ;
const primitive = getPrimitives ( data ) [ 0 ] ;
const normals = primitive . normals ;
const normalsLength = normals . length / 3 ;
for ( let i = 0 ; i < normalsLength ; ++ i ) {
const normalX = normals . get ( i * 3 ) ;
const normalY = normals . get ( i * 3 + 1 ) ;
const normalZ = normals . get ( i * 3 + 2 ) ;
const normal = Cartesian3 . fromElements ( normalX , normalY , normalZ , scratchNormal ) ;
expect ( CesiumMath . equalsEpsilon ( Cartesian3 . magnitude ( normal ) , 1.0 , CesiumMath . EPSILON5 ) ) . toBe ( true ) ;
}
} ) ;
it ( 'loads obj with uvs' , async ( ) => {
const data = await loadObj ( objUvsPath , options ) ;
const primitive = getPrimitives ( data ) [ 0 ] ;
expect ( primitive . positions . length / 3 ) . toBe ( 20 ) ;
expect ( primitive . normals . length / 3 ) . toBe ( 0 ) ;
expect ( primitive . uvs . length / 2 ) . toBe ( 20 ) ;
} ) ;
it ( 'loads obj with negative indices' , async ( ) => {
const results = [
await loadObj ( objPositionsOnlyPath , options ) ,
await loadObj ( objNegativeIndicesPath , options )
] ;
const positionsReference = getPrimitives ( results [ 0 ] ) [ 0 ] . positions . toFloatBuffer ( ) ;
const positions = getPrimitives ( results [ 1 ] ) [ 0 ] . positions . toFloatBuffer ( ) ;
expect ( positions ) . toEqual ( positionsReference ) ;
} ) ;
it ( 'loads obj with triangle faces' , async ( ) => {
const data = await loadObj ( objTrianglesPath , options ) ;
const primitive = getPrimitives ( data ) [ 0 ] ;
expect ( primitive . positions . length / 3 ) . toBe ( 24 ) ;
expect ( primitive . indices . length ) . toBe ( 36 ) ;
} ) ;
it ( 'loads obj with objects' , async ( ) => {
const data = await loadObj ( objObjectsPath , options ) ;
const nodes = data . nodes ;
expect ( nodes . length ) . toBe ( 3 ) ;
expect ( nodes [ 0 ] . name ) . toBe ( 'CubeBlue' ) ;
expect ( nodes [ 1 ] . name ) . toBe ( 'CubeGreen' ) ;
expect ( nodes [ 2 ] . name ) . toBe ( 'CubeRed' ) ;
const primitives = getPrimitives ( data ) ;
expect ( primitives . length ) . toBe ( 3 ) ;
expect ( primitives [ 0 ] . material ) . toBe ( 'Blue' ) ;
expect ( primitives [ 1 ] . material ) . toBe ( 'Green' ) ;
expect ( primitives [ 2 ] . material ) . toBe ( 'Red' ) ;
} ) ;
it ( 'loads obj with groups' , async ( ) => {
const data = await loadObj ( objGroupsPath , options ) ;
const nodes = data . nodes ;
expect ( nodes . length ) . toBe ( 3 ) ;
expect ( nodes [ 0 ] . name ) . toBe ( 'CubeBlue' ) ;
expect ( nodes [ 1 ] . name ) . toBe ( 'CubeGreen' ) ;
expect ( nodes [ 2 ] . name ) . toBe ( 'CubeRed' ) ;
const primitives = getPrimitives ( data ) ;
expect ( primitives . length ) . toBe ( 3 ) ;
expect ( primitives [ 0 ] . material ) . toBe ( 'Blue' ) ;
expect ( primitives [ 1 ] . material ) . toBe ( 'Green' ) ;
expect ( primitives [ 2 ] . material ) . toBe ( 'Red' ) ;
} ) ;
it ( 'loads obj with objects and groups' , async ( ) => {
const data = await loadObj ( objObjectsGroupsPath , options ) ;
const nodes = data . nodes ;
expect ( nodes . length ) . toBe ( 3 ) ;
expect ( nodes [ 0 ] . name ) . toBe ( 'CubeBlue' ) ;
expect ( nodes [ 1 ] . name ) . toBe ( 'CubeGreen' ) ;
expect ( nodes [ 2 ] . name ) . toBe ( 'CubeRed' ) ;
const meshes = getMeshes ( data ) ;
expect ( meshes . length ) . toBe ( 3 ) ;
expect ( meshes [ 0 ] . name ) . toBe ( 'CubeBlue_CubeBlue_Blue' ) ;
expect ( meshes [ 1 ] . name ) . toBe ( 'CubeGreen_CubeGreen_Green' ) ;
expect ( meshes [ 2 ] . name ) . toBe ( 'CubeRed_CubeRed_Red' ) ;
const primitives = getPrimitives ( data ) ;
expect ( primitives . length ) . toBe ( 3 ) ;
expect ( primitives [ 0 ] . material ) . toBe ( 'Blue' ) ;
expect ( primitives [ 1 ] . material ) . toBe ( 'Green' ) ;
expect ( primitives [ 2 ] . material ) . toBe ( 'Red' ) ;
2017-03-13 15:28:51 -04:00
} ) ;
2017-12-29 11:55:21 -05:00
function loadsObjWithObjectsGroupsAndMaterials ( data ) {
2019-02-05 20:59:09 -05:00
const nodes = data . nodes ;
2017-12-29 11:55:21 -05:00
expect ( nodes . length ) . toBe ( 1 ) ;
expect ( nodes [ 0 ] . name ) . toBe ( 'Cube' ) ;
2019-02-05 20:59:09 -05:00
const meshes = getMeshes ( data ) ;
2017-12-29 11:55:21 -05:00
expect ( meshes . length ) . toBe ( 3 ) ;
expect ( meshes [ 0 ] . name ) . toBe ( 'Blue' ) ;
expect ( meshes [ 1 ] . name ) . toBe ( 'Green' ) ;
expect ( meshes [ 2 ] . name ) . toBe ( 'Red' ) ;
2019-02-05 20:59:09 -05:00
const primitives = getPrimitives ( data ) ;
2017-12-29 11:55:21 -05:00
expect ( primitives . length ) . toBe ( 6 ) ;
expect ( primitives [ 0 ] . material ) . toBe ( 'Blue' ) ;
expect ( primitives [ 1 ] . material ) . toBe ( 'Green' ) ;
expect ( primitives [ 2 ] . material ) . toBe ( 'Green' ) ;
expect ( primitives [ 3 ] . material ) . toBe ( 'Red' ) ;
expect ( primitives [ 4 ] . material ) . toBe ( 'Red' ) ;
expect ( primitives [ 5 ] . material ) . toBe ( 'Blue' ) ;
}
2019-02-05 20:59:09 -05:00
it ( 'loads obj with objects, groups, and materials' , async ( ) => {
const data = await loadObj ( objObjectsGroupsMaterialsPath , options ) ;
loadsObjWithObjectsGroupsAndMaterials ( data ) ;
2017-12-29 11:55:21 -05:00
} ) ;
2019-02-05 20:59:09 -05:00
it ( 'loads obj with objects, groups, and materials (2)' , async ( ) => {
2017-12-29 11:55:21 -05:00
// The usemtl lines are placed in an unordered fashion but
// should produce the same result as the previous test
2019-02-05 20:59:09 -05:00
const data = await loadObj ( objObjectsGroupsMaterialsPath2 , options ) ;
loadsObjWithObjectsGroupsAndMaterials ( data ) ;
2017-12-29 11:55:21 -05:00
} ) ;
2019-02-05 20:59:09 -05:00
it ( 'loads obj with concave face containing 5 vertices' , async ( ) => {
const data = await loadObj ( objConcavePath , options ) ;
const primitive = getPrimitives ( data ) [ 0 ] ;
expect ( primitive . positions . length / 3 ) . toBe ( 30 ) ;
expect ( primitive . indices . length ) . toBe ( 48 ) ;
2017-06-14 16:55:03 -04:00
} ) ;
2019-02-05 20:59:09 -05:00
it ( 'loads obj with usemtl only' , async ( ) => {
const data = await loadObj ( objUsemtlPath , options ) ;
const nodes = data . nodes ;
expect ( nodes . length ) . toBe ( 1 ) ;
expect ( nodes [ 0 ] . name ) . toBe ( 'Node' ) ; // default name
2017-03-13 15:28:51 -04:00
2019-02-05 20:59:09 -05:00
const meshes = getMeshes ( data ) ;
expect ( meshes . length ) . toBe ( 1 ) ;
expect ( meshes [ 0 ] . name ) . toBe ( 'Node-Mesh' ) ;
2017-03-13 15:28:51 -04:00
2019-02-05 20:59:09 -05:00
const primitives = getPrimitives ( data ) ;
expect ( primitives . length ) . toBe ( 3 ) ;
expect ( primitives [ 0 ] . material ) . toBe ( 'Blue' ) ;
expect ( primitives [ 1 ] . material ) . toBe ( 'Green' ) ;
expect ( primitives [ 2 ] . material ) . toBe ( 'Red' ) ;
2017-03-13 15:28:51 -04:00
} ) ;
2019-02-05 20:59:09 -05:00
it ( 'loads obj with no materials' , async ( ) => {
const data = await loadObj ( objNoMaterialsPath , options ) ;
const nodes = data . nodes ;
expect ( nodes . length ) . toBe ( 1 ) ;
expect ( nodes [ 0 ] . name ) . toBe ( 'Node' ) ; // default name
2017-03-13 15:28:51 -04:00
2019-02-05 20:59:09 -05:00
const primitives = getPrimitives ( data ) ;
expect ( primitives . length ) . toBe ( 1 ) ;
2017-03-13 15:28:51 -04:00
} ) ;
2019-02-05 20:59:09 -05:00
it ( 'loads obj with multiple materials' , async ( ) => {
2017-03-13 15:28:51 -04:00
// The usemtl markers are interleaved, but should condense to just three primitives
2019-02-05 20:59:09 -05:00
const data = await loadObj ( objMultipleMaterialsPath , options ) ;
const nodes = data . nodes ;
expect ( nodes . length ) . toBe ( 1 ) ;
const primitives = getPrimitives ( data ) ;
expect ( primitives . length ) . toBe ( 3 ) ;
expect ( primitives [ 0 ] . indices . length ) . toBe ( 12 ) ;
expect ( primitives [ 1 ] . indices . length ) . toBe ( 12 ) ;
expect ( primitives [ 2 ] . indices . length ) . toBe ( 12 ) ;
expect ( primitives [ 0 ] . material ) . toBe ( 'Red' ) ;
expect ( primitives [ 1 ] . material ) . toBe ( 'Green' ) ;
expect ( primitives [ 2 ] . material ) . toBe ( 'Blue' ) ;
for ( let i = 0 ; i < 3 ; ++ i ) {
const indices = primitives [ i ] . indices ;
for ( let j = 0 ; j < indices . length ; ++ j ) {
expect ( indices . get ( j ) ) . toBeLessThan ( 8 ) ;
}
}
} ) ;
it ( 'loads obj uncleaned' , async ( ) => {
2017-03-13 15:28:51 -04:00
// Obj with extraneous o, g, and usemtl lines
// Also tests handling of o and g lines with the same names
2019-02-05 20:59:09 -05:00
const data = await loadObj ( objUncleanedPath , options ) ;
const nodes = data . nodes ;
const meshes = getMeshes ( data ) ;
const primitives = getPrimitives ( data ) ;
expect ( nodes . length ) . toBe ( 1 ) ;
expect ( meshes . length ) . toBe ( 1 ) ;
expect ( primitives . length ) . toBe ( 1 ) ;
expect ( nodes [ 0 ] . name ) . toBe ( 'Cube' ) ;
expect ( meshes [ 0 ] . name ) . toBe ( 'Cube_1' ) ;
} ) ;
it ( 'loads obj with multiple mtllibs' , async ( ) => {
const data = await loadObj ( objMtllibPath , options ) ;
const materials = data . materials ;
expect ( materials . length ) . toBe ( 3 ) ;
// .mtl files are loaded in an arbitrary order, so sort for testing purposes
materials . sort ( ( a , b ) => {
return a . name . localeCompare ( b . name ) ;
} ) ;
expect ( materials [ 0 ] . name ) . toBe ( 'Blue' ) ;
expect ( materials [ 0 ] . pbrMetallicRoughness . baseColorFactor ) . toEqual ( [ 0.0 , 0.0 , 0.64 , 1.0 ] ) ;
expect ( materials [ 1 ] . name ) . toBe ( 'Green' ) ;
expect ( materials [ 1 ] . pbrMetallicRoughness . baseColorFactor ) . toEqual ( [ 0.0 , 0.64 , 0.0 , 1.0 ] ) ;
expect ( materials [ 2 ] . name ) . toBe ( 'Red' ) ;
expect ( materials [ 2 ] . pbrMetallicRoughness . baseColorFactor ) . toEqual ( [ 0.64 , 0.0 , 0.0 , 1.0 ] ) ;
} ) ;
it ( 'loads obj with mtllib paths with spaces' , async ( ) => {
const data = await loadObj ( objMtllibSpacesPath , options ) ;
const materials = data . materials ;
expect ( materials . length ) . toBe ( 3 ) ;
// .mtl files are loaded in an arbitrary order, so sort for testing purposes
materials . sort ( ( a , b ) => {
return a . name . localeCompare ( b . name ) ;
} ) ;
expect ( materials [ 0 ] . name ) . toBe ( 'Blue' ) ;
expect ( materials [ 0 ] . pbrMetallicRoughness . baseColorFactor ) . toEqual ( [ 0.0 , 0.0 , 0.64 , 1.0 ] ) ;
expect ( materials [ 1 ] . name ) . toBe ( 'Green' ) ;
expect ( materials [ 1 ] . pbrMetallicRoughness . baseColorFactor ) . toEqual ( [ 0.0 , 0.64 , 0.0 , 1.0 ] ) ;
expect ( materials [ 2 ] . name ) . toBe ( 'Red' ) ;
expect ( materials [ 2 ] . pbrMetallicRoughness . baseColorFactor ) . toEqual ( [ 0.64 , 0.0 , 0.0 , 1.0 ] ) ;
} ) ;
it ( 'loads obj with missing mtllib' , async ( ) => {
const spy = jasmine . createSpy ( 'logger' ) ;
2017-07-29 13:23:33 -04:00
options . logger = spy ;
2019-02-05 20:59:09 -05:00
const data = await loadObj ( objMissingMtllibPath , options ) ;
expect ( data . materials . length ) . toBe ( 0 ) ;
expect ( spy . calls . argsFor ( 0 ) [ 0 ] . indexOf ( 'ENOENT' ) >= 0 ) . toBe ( true ) ;
2019-10-26 20:42:12 -04:00
expect ( spy . calls . argsFor ( 0 ) [ 0 ] . indexOf ( path . resolve ( '/box.mtl' ) ) >= 0 ) . toBe ( true ) ;
2019-02-05 20:59:09 -05:00
expect ( spy . calls . argsFor ( 1 ) [ 0 ] . indexOf ( 'Attempting to read the material file from within the obj directory instead.' ) >= 0 ) . toBe ( true ) ;
expect ( spy . calls . argsFor ( 2 ) [ 0 ] . indexOf ( 'ENOENT' ) >= 0 ) . toBe ( true ) ;
expect ( spy . calls . argsFor ( 3 ) [ 0 ] . indexOf ( 'Could not read material file' ) >= 0 ) . toBe ( true ) ;
2017-04-04 16:45:21 -04:00
} ) ;
2019-02-05 20:59:09 -05:00
it ( 'loads obj with missing usemtl' , async ( ) => {
const data = await loadObj ( objMissingUsemtlPath , options ) ;
expect ( data . materials . length ) . toBe ( 1 ) ;
expect ( data . nodes [ 0 ] . meshes [ 0 ] . primitives [ 0 ] . material ) . toBe ( 'Material' ) ;
2018-03-06 19:22:06 -05:00
} ) ;
2019-02-10 09:45:46 -05:00
it ( 'loads obj with unnamed material' , async ( ) => {
const data = await loadObj ( objUnnamedMaterialPath , options ) ;
expect ( data . materials . length ) . toBe ( 1 ) ;
expect ( data . nodes [ 0 ] . meshes [ 0 ] . primitives [ 0 ] . material ) . toBe ( '' ) ;
2019-01-03 09:29:02 -05:00
} ) ;
2019-02-05 20:59:09 -05:00
it ( 'loads .mtl outside of the obj directory' , async ( ) => {
const data = await loadObj ( objExternalResourcesPath , options ) ;
const materials = data . materials ;
expect ( materials . length ) . toBe ( 2 ) ;
2017-05-04 17:58:13 -04:00
2019-02-05 20:59:09 -05:00
// .mtl files are loaded in an arbitrary order, so find the "MaterialTextured" material
const materialTextured = materials [ 0 ] . name === 'MaterialTextured' ? materials [ 0 ] : materials [ 1 ] ;
const baseColorTexture = materialTextured . pbrMetallicRoughness . baseColorTexture ;
expect ( baseColorTexture . source ) . toBeDefined ( ) ;
expect ( baseColorTexture . name ) . toEqual ( 'cesium' ) ;
2017-04-04 16:45:21 -04:00
} ) ;
2019-02-05 20:59:09 -05:00
it ( 'does not load .mtl outside of the obj directory when secure is true' , async ( ) => {
const spy = jasmine . createSpy ( 'logger' ) ;
2017-07-29 13:23:33 -04:00
options . logger = spy ;
2017-04-10 17:57:56 -04:00
options . secure = true ;
2019-02-05 20:59:09 -05:00
const data = await loadObj ( objExternalResourcesPath , options ) ;
expect ( data . materials . length ) . toBe ( 1 ) ; // obj references 2 materials, one of which is outside the input directory
expect ( spy . calls . argsFor ( 0 ) [ 0 ] . indexOf ( 'The material file is outside of the obj directory and the secure flag is true. Attempting to read the material file from within the obj directory instead.' ) >= 0 ) . toBe ( true ) ;
expect ( spy . calls . argsFor ( 1 ) [ 0 ] . indexOf ( 'ENOENT' ) >= 0 ) . toBe ( true ) ;
expect ( spy . calls . argsFor ( 2 ) [ 0 ] . indexOf ( 'Could not read material file' ) >= 0 ) . toBe ( true ) ;
2017-03-13 15:28:51 -04:00
} ) ;
2019-02-05 20:59:09 -05:00
it ( 'loads .mtl from root directory when the .mtl path does not exist' , async ( ) => {
const data = await loadObj ( objResourcesInRootPath , options ) ;
const baseColorTexture = data . materials [ 0 ] . pbrMetallicRoughness . baseColorTexture ;
expect ( baseColorTexture . name ) . toBe ( 'cesium' ) ;
expect ( baseColorTexture . source ) . toBeDefined ( ) ;
2017-11-17 15:07:52 -05:00
} ) ;
2019-02-05 20:59:09 -05:00
it ( 'loads .mtl from root directory when the .mtl path is outside of the obj directory and secure is true' , async ( ) => {
2017-11-29 14:21:59 -05:00
options . secure = true ;
2019-02-05 20:59:09 -05:00
const data = await loadObj ( objExternalResourcesInRootPath , options ) ;
const materials = data . materials ;
expect ( materials . length ) . toBe ( 2 ) ;
2017-11-29 14:21:59 -05:00
2019-02-05 20:59:09 -05:00
// .mtl files are loaded in an arbitrary order, so find the "MaterialTextured" material
const materialTextured = materials [ 0 ] . name === 'MaterialTextured' ? materials [ 0 ] : materials [ 1 ] ;
const baseColorTexture = materialTextured . pbrMetallicRoughness . baseColorTexture ;
expect ( baseColorTexture . source ) . toBeDefined ( ) ;
expect ( baseColorTexture . name ) . toEqual ( 'cesium' ) ;
2017-03-13 15:28:51 -04:00
} ) ;
2019-02-05 20:59:09 -05:00
it ( 'loads obj with texture' , async ( ) => {
const data = await loadObj ( objTexturedPath , options ) ;
const baseColorTexture = data . materials [ 0 ] . pbrMetallicRoughness . baseColorTexture ;
expect ( baseColorTexture . name ) . toBe ( 'cesium' ) ;
expect ( baseColorTexture . source ) . toBeDefined ( ) ;
2017-03-13 15:28:51 -04:00
} ) ;
2019-02-05 20:59:09 -05:00
it ( 'loads obj with missing texture' , async ( ) => {
const spy = jasmine . createSpy ( 'logger' ) ;
2017-07-29 13:23:33 -04:00
options . logger = spy ;
2017-03-13 15:28:51 -04:00
2019-02-05 20:59:09 -05:00
const data = await loadObj ( objMissingTexturePath , options ) ;
const baseColorTexture = data . materials [ 0 ] . pbrMetallicRoughness . baseColorTexture ;
expect ( baseColorTexture ) . toBeUndefined ( ) ;
expect ( spy . calls . argsFor ( 0 ) [ 0 ] . indexOf ( 'ENOENT' ) >= 0 ) . toBe ( true ) ;
2019-10-26 20:42:12 -04:00
expect ( spy . calls . argsFor ( 0 ) [ 0 ] . indexOf ( path . resolve ( '/cesium.png' ) ) >= 0 ) . toBe ( true ) ;
2019-02-05 20:59:09 -05:00
expect ( spy . calls . argsFor ( 1 ) [ 0 ] . indexOf ( 'Attempting to read the texture file from within the obj directory instead.' ) >= 0 ) . toBe ( true ) ;
expect ( spy . calls . argsFor ( 2 ) [ 0 ] . indexOf ( 'ENOENT' ) >= 0 ) . toBe ( true ) ;
expect ( spy . calls . argsFor ( 3 ) [ 0 ] . indexOf ( 'Could not read texture file' ) >= 0 ) . toBe ( true ) ;
} ) ;
it ( 'loads obj with subdirectories' , async ( ) => {
const data = await loadObj ( objSubdirectoriesPath , options ) ;
const baseColorTexture = data . materials [ 0 ] . pbrMetallicRoughness . baseColorTexture ;
expect ( baseColorTexture . name ) . toBe ( 'cesium' ) ;
expect ( baseColorTexture . source ) . toBeDefined ( ) ;
} ) ;
it ( 'loads obj with windows paths' , async ( ) => {
const data = await loadObj ( objWindowsPaths , options ) ;
const baseColorTexture = data . materials [ 0 ] . pbrMetallicRoughness . baseColorTexture ;
expect ( baseColorTexture . name ) . toBe ( 'cesium' ) ;
expect ( baseColorTexture . source ) . toBeDefined ( ) ;
} ) ;
it ( 'separates faces that don\'t use the same attributes as other faces in the primitive' , async ( ) => {
const data = await loadObj ( objMixedAttributesPath , options ) ;
const primitives = getPrimitives ( data ) ;
expect ( primitives . length ) . toBe ( 4 ) ;
expect ( primitives [ 0 ] . indices . length ) . toBe ( 18 ) ; // 6 faces
expect ( primitives [ 1 ] . indices . length ) . toBe ( 6 ) ; // 2 faces
expect ( primitives [ 2 ] . indices . length ) . toBe ( 6 ) ; // 2 faces
expect ( primitives [ 3 ] . indices . length ) . toBe ( 6 ) ; // 2 faces
2019-08-19 16:33:12 -07:00
} ) ;
2017-04-20 14:41:39 -04:00
function getFirstPosition ( data ) {
2019-08-19 16:33:12 -07:00
const primitive = getPrimitives ( data ) [ 0 ] ;
return new Cartesian3 ( primitive . positions . get ( 0 ) , primitive . positions . get ( 1 ) , primitive . positions . get ( 2 ) ) ;
2017-04-20 14:41:39 -04:00
}
function getFirstNormal ( data ) {
2019-08-19 16:33:12 -07:00
const primitive = getPrimitives ( data ) [ 0 ] ;
return new Cartesian3 ( primitive . normals . get ( 0 ) , primitive . normals . get ( 1 ) , primitive . normals . get ( 2 ) ) ;
2017-04-20 14:41:39 -04:00
}
2019-08-19 16:33:12 -07:00
async function checkAxisConversion ( inputUpAxis , outputUpAxis , position , normal ) {
2019-08-20 10:32:32 -07:00
const sameAxis = ( inputUpAxis === outputUpAxis ) ;
2017-04-20 14:41:39 -04:00
options . inputUpAxis = inputUpAxis ;
options . outputUpAxis = outputUpAxis ;
2019-08-19 16:33:12 -07:00
const data = await loadObj ( objRotatedUrl , options ) ;
const rotatedPosition = getFirstPosition ( data ) ;
const rotatedNormal = getFirstNormal ( data ) ;
if ( sameAxis ) {
expect ( rotatedPosition ) . toEqual ( position ) ;
expect ( rotatedNormal ) . toEqual ( normal ) ;
} else {
expect ( rotatedPosition ) . not . toEqual ( position ) ;
expect ( rotatedNormal ) . not . toEqual ( normal ) ;
}
2017-04-20 14:41:39 -04:00
}
2019-08-19 16:33:12 -07:00
it ( 'performs up axis conversion' , async ( ) => {
const data = await loadObj ( objRotatedUrl , options ) ;
const position = getFirstPosition ( data ) ;
const normal = getFirstNormal ( data ) ;
const axes = [ 'X' , 'Y' , 'Z' ] ;
const axesLength = axes . length ;
for ( let i = 0 ; i < axesLength ; ++ i ) {
for ( let j = 0 ; j < axesLength ; ++ j ) {
await checkAxisConversion ( axes [ i ] , axes [ j ] , position , normal ) ;
}
}
2019-02-05 20:59:09 -05:00
} ) ;
2019-10-27 15:26:40 -04:00
it ( 'ignores missing normals and uvs' , async ( ) => {
2019-10-26 20:15:10 -04:00
const data = await loadObj ( objMissingAttributesPath , options ) ;
const primitive = getPrimitives ( data ) [ 0 ] ;
expect ( primitive . positions . length ) . toBeGreaterThan ( 0 ) ;
expect ( primitive . normals . length ) . toBe ( 0 ) ;
expect ( primitive . uvs . length ) . toBe ( 0 ) ;
} ) ;
2019-10-27 15:00:35 -04:00
it ( 'throws when position index is out of bounds' , async ( ) => {
let thrownError ;
try {
await loadObj ( objIncompletePositionsPath , options ) ;
} catch ( e ) {
thrownError = e ;
}
expect ( thrownError ) . toEqual ( new RuntimeError ( 'Position index 1 is out of bounds' ) ) ;
} ) ;
it ( 'throws when normal index is out of bounds' , async ( ) => {
let thrownError ;
try {
await loadObj ( objIncompleteNormalsPath , options ) ;
} catch ( e ) {
thrownError = e ;
}
expect ( thrownError ) . toEqual ( new RuntimeError ( 'Normal index 1 is out of bounds' ) ) ;
} ) ;
it ( 'throws when uv index is out of bounds' , async ( ) => {
let thrownError ;
try {
await loadObj ( objIncompleteUvsPath , options ) ;
} catch ( e ) {
thrownError = e ;
}
expect ( thrownError ) . toEqual ( new RuntimeError ( 'UV index 1 is out of bounds' ) ) ;
} ) ;
2019-02-05 20:59:09 -05:00
it ( 'throws when file has invalid contents' , async ( ) => {
let thrownError ;
try {
await loadObj ( objInvalidContentsPath , options ) ;
} catch ( e ) {
thrownError = e ;
}
expect ( thrownError ) . toEqual ( new RuntimeError ( objInvalidContentsPath + ' does not have any geometry data' ) ) ;
} ) ;
it ( 'throw when reading invalid file' , async ( ) => {
let thrownError ;
try {
await loadObj ( objInvalidPath , options ) ;
} catch ( e ) {
thrownError = e ;
}
expect ( thrownError . message . startsWith ( 'ENOENT: no such file or directory' ) ) . toBe ( true ) ;
2017-03-13 15:28:51 -04:00
} ) ;
} ) ;