Merge branch 'dev'

This commit is contained in:
Viktor Kovacs 2021-05-03 18:28:40 +02:00
commit 92b993f5f4
58 changed files with 4622 additions and 3600 deletions

View File

@ -21,6 +21,7 @@
"globals" : {
"OV" : true,
"THREE" : false,
"rhino3dm" : false,
"TextEncoder" : false,
"TextDecoder" : false,
"XMLHttpRequest" : false,

View File

@ -23,6 +23,7 @@ The repository is separated into two parts. See more information in the [Develop
- stl (text and binary)
- ply (text and binary)
- gltf (text and binary)
- 3dm (experimental)
- off (text only)
### Export
@ -31,24 +32,29 @@ The repository is separated into two parts. See more information in the [Develop
- stl (text and binary)
- ply (text and binary)
- gltf (text and binary)
- 3dm (experimental)
- off (text only)
## Features
- Load model:
- Select files from a file browser dialog
- Drag and drop files from your computer
- Specify files by web url
- Specify files by web url in hash parameters
- Select files from a file browser dialog.
- Drag and drop files from your computer.
- Specify files by web url.
- Specify files by web url in hash parameters.
- Explore model:
- Orbit, pan, zoom
- Set up direction
- Fit to window
- Orbit, pan, zoom.
- Set up direction.
- Fit to window.
- Investigate model:
- List used and missing files
- List all materials and meshes
- Show/hide and zoom to a specific mesh
- List materials used by a specific mesh
- Show model information (model size, vertex and polygon count)
- Export model to various format
- Embed viewer in your website
- List used and missing files.
- List all materials and meshes.
- Show/hide and zoom to a specific mesh.
- List materials used by a specific mesh.
- Show model information (model size, vertex and polygon count).
- Export model to various format.
- Embed viewer in your website.
## External Libraries
Online 3D Viewer uses these wonderful libraries: [jquery](https://github.com/jquery/jquery), [three.js](https://github.com/mrdoob/three.js), [rhino3dm](https://github.com/mcneel/rhino3dm).

21
libs/rhino3dm.license.txt Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Robert McNeel & Associates
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

8
libs/rhino3dm.min.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
libs/rhino3dm.wasm Normal file

Binary file not shown.

View File

@ -1,7 +1,7 @@
{
"name": "online-3d-viewer",
"description": "Online 3D Viewer",
"version": "0.7.7",
"version": "0.7.8",
"repository": "github:kovacsv/Online3DViewer",
"license": "MIT",
"devDependencies": {

View File

@ -11,16 +11,32 @@ OV.Exporter = class
];
}
Export (model, format, extension)
AddExporter (exporter)
{
let files = [];
this.exporters.push (exporter);
}
Export (model, format, extension, callbacks)
{
let exporter = null;
for (let i = 0; i < this.exporters.length; i++) {
let exporter = this.exporters[i];
if (exporter.CanExport (format, extension)) {
exporter.Export (model, format, files);
let currentExporter = this.exporters[i];
if (currentExporter.CanExport (format, extension)) {
exporter = currentExporter;
break;
}
}
return files;
if (exporter === null) {
callbacks.onError ();
return;
}
exporter.Export (model, format, function (files) {
if (files.length === 0) {
callbacks.onError ();
} else {
callbacks.onSuccess (files);
}
});
}
};

View File

@ -39,12 +39,15 @@ OV.ExporterBase = class
return false;
}
Export (model, format, files)
Export (model, format, onFinish)
{
this.ExportContent (model, format, files);
let files = [];
this.ExportContent (model, format, files, function () {
onFinish (files);
});
}
ExportContent (model, format, files)
ExportContent (model, format, files, onFinish)
{
}

View File

@ -20,13 +20,14 @@ OV.ExporterGltf = class extends OV.ExporterBase
return (format === OV.FileFormat.Text && extension === 'gltf') || (format === OV.FileFormat.Binary && extension === 'glb');
}
ExportContent (model, format, files)
ExportContent (model, format, files, onFinish)
{
if (format === OV.FileFormat.Text) {
this.ExportAsciiContent (model, files);
} else if (format === OV.FileFormat.Binary) {
this.ExportBinaryContent (model, files);
}
onFinish ();
}
ExportAsciiContent (model, files)
@ -195,9 +196,8 @@ OV.ExporterGltf = class extends OV.ExporterBase
let writer = new OV.BinaryWriter (mainBufferSize, true);
for (let meshIndex = 0; meshIndex < meshDataArr.length; meshIndex++) {
let meshData = meshDataArr[meshIndex];
let primitives = meshData.buffer.primitives;
for (let primitiveIndex = 0; primitiveIndex < primitives.length; primitiveIndex++) {
let primitive = primitives[primitiveIndex];
for (let primitiveIndex = 0; primitiveIndex < meshData.buffer.PrimitiveCount (); primitiveIndex++) {
let primitive = meshData.buffer.GetPrimitive (primitiveIndex);
let offset = writer.GetPosition ();
for (let i = 0; i < primitive.indices.length; i++) {
writer.WriteUnsignedInteger32 (primitive.indices[i]);
@ -408,6 +408,7 @@ OV.ExporterGltf = class extends OV.ExporterBase
roughnessFactor : 1.0
},
emissiveFactor : ColorToRGB (material.emissive),
doubleSided : true,
alphaMode : 'OPAQUE'
};

View File

@ -1,115 +1,116 @@
OV.ExporterObj = class extends OV.ExporterBase
{
constructor ()
{
super ();
}
constructor ()
{
super ();
}
CanExport (format, extension)
{
return format === OV.FileFormat.Text && extension === 'obj';
}
ExportContent (model, format, files)
{
function WriteTexture (mtlWriter, keyword, texture, files)
{
if (texture === null || !texture.IsValid ()) {
return;
}
let fileName = OV.GetFileName (texture.name);
mtlWriter.WriteArrayLine ([keyword, fileName]);
ExportContent (model, format, files, onFinish)
{
function WriteTexture (mtlWriter, keyword, texture, files)
{
if (texture === null || !texture.IsValid ()) {
return;
}
let fileName = OV.GetFileName (texture.name);
mtlWriter.WriteArrayLine ([keyword, fileName]);
let fileIndex = files.findIndex (function (file) {
return file.GetName () === fileName;
});
if (fileIndex === -1) {
let textureFile = new OV.ExportedFile (fileName);
textureFile.SetContent (texture.buffer);
files.push (textureFile);
}
}
let fileIndex = files.findIndex (function (file) {
return file.GetName () === fileName;
});
if (fileIndex === -1) {
let textureFile = new OV.ExportedFile (fileName);
textureFile.SetContent (texture.buffer);
files.push (textureFile);
}
}
let mtlFile = new OV.ExportedFile ('model.mtl');
let objFile = new OV.ExportedFile ('model.obj');
let mtlFile = new OV.ExportedFile ('model.mtl');
let objFile = new OV.ExportedFile ('model.obj');
files.push (mtlFile);
files.push (objFile);
files.push (mtlFile);
files.push (objFile);
let mtlWriter = new OV.TextWriter ();
mtlWriter.WriteLine (this.GetHeaderText ());
for (let materialIndex = 0; materialIndex < model.MaterialCount (); materialIndex++) {
let material = model.GetMaterial (materialIndex);
mtlWriter.WriteArrayLine (['newmtl', this.GetExportedMaterialName (material.name)]);
mtlWriter.WriteArrayLine (['Ka', material.ambient.r / 255.0, material.ambient.g / 255.0, material.ambient.b / 255.0]);
mtlWriter.WriteArrayLine (['Kd', material.diffuse.r / 255.0, material.diffuse.g / 255.0, material.diffuse.b / 255.0]);
mtlWriter.WriteArrayLine (['Ks', material.specular.r / 255.0, material.specular.g / 255.0, material.specular.b / 255.0]);
mtlWriter.WriteArrayLine (['Ns', material.shininess * 100.0]);
mtlWriter.WriteArrayLine (['d', material.opacity]);
WriteTexture (mtlWriter, 'map_Kd', material.diffuseMap, files);
WriteTexture (mtlWriter, 'map_Ks', material.specularMap, files);
WriteTexture (mtlWriter, 'bump', material.bumpMap, files);
}
mtlFile.SetContent (mtlWriter.GetText ());
let mtlWriter = new OV.TextWriter ();
mtlWriter.WriteLine (this.GetHeaderText ());
for (let materialIndex = 0; materialIndex < model.MaterialCount (); materialIndex++) {
let material = model.GetMaterial (materialIndex);
mtlWriter.WriteArrayLine (['newmtl', this.GetExportedMaterialName (material.name)]);
mtlWriter.WriteArrayLine (['Ka', material.ambient.r / 255.0, material.ambient.g / 255.0, material.ambient.b / 255.0]);
mtlWriter.WriteArrayLine (['Kd', material.diffuse.r / 255.0, material.diffuse.g / 255.0, material.diffuse.b / 255.0]);
mtlWriter.WriteArrayLine (['Ks', material.specular.r / 255.0, material.specular.g / 255.0, material.specular.b / 255.0]);
mtlWriter.WriteArrayLine (['Ns', material.shininess * 1000.0]);
mtlWriter.WriteArrayLine (['d', material.opacity]);
WriteTexture (mtlWriter, 'map_Kd', material.diffuseMap, files);
WriteTexture (mtlWriter, 'map_Ks', material.specularMap, files);
WriteTexture (mtlWriter, 'bump', material.bumpMap, files);
}
mtlFile.SetContent (mtlWriter.GetText ());
let objWriter = new OV.TextWriter ();
objWriter.WriteLine (this.GetHeaderText ());
objWriter.WriteArrayLine (['mtllib', mtlFile.GetName ()]);
let vertexOffset = 0;
let normalOffset = 0;
let uvOffset = 0;
let usedMaterialName = null;
for (let meshIndex = 0; meshIndex < model.MeshCount (); meshIndex++) {
let mesh = model.GetMesh (meshIndex);
objWriter.WriteArrayLine (['g', this.GetExportedMeshName (mesh.GetName ())]);
for (let vertexIndex = 0; vertexIndex < mesh.VertexCount (); vertexIndex++) {
let vertex = mesh.GetVertex (vertexIndex);
objWriter.WriteArrayLine (['v', vertex.x, vertex.y, vertex.z]);
}
for (let normalIndex = 0; normalIndex < mesh.NormalCount (); normalIndex++) {
let normal = mesh.GetNormal (normalIndex);
objWriter.WriteArrayLine (['vn', normal.x, normal.y, normal.z]);
}
for (let textureUVIndex = 0; textureUVIndex < mesh.TextureUVCount (); textureUVIndex++) {
let uv = mesh.GetTextureUV (textureUVIndex);
objWriter.WriteArrayLine (['vt', uv.x, uv.y]);
}
for (let triangleIndex = 0; triangleIndex < mesh.TriangleCount (); triangleIndex++) {
let triangle = mesh.GetTriangle (triangleIndex);
let v0 = triangle.v0 + vertexOffset + 1;
let v1 = triangle.v1 + vertexOffset + 1;
let v2 = triangle.v2 + vertexOffset + 1;
let n0 = triangle.n0 + normalOffset + 1;
let n1 = triangle.n1 + normalOffset + 1;
let n2 = triangle.n2 + normalOffset + 1;
if (triangle.mat !== null) {
let material = model.GetMaterial (triangle.mat);
let materialName = this.GetExportedMaterialName (material.name);
if (materialName !== usedMaterialName) {
objWriter.WriteArrayLine (['usemtl', materialName]);
usedMaterialName = materialName;
}
}
let u0 = '';
let u1 = '';
let u2 = '';
if (triangle.HasTextureUVs ()) {
u0 = triangle.u0 + uvOffset + 1;
u1 = triangle.u1 + uvOffset + 1;
u2 = triangle.u2 + uvOffset + 1;
}
objWriter.WriteArrayLine (['f', [v0, u0, n0].join ('/'), [v1, u1, n1].join ('/'), [v2, u2, n2].join ('/')]);
}
vertexOffset += mesh.VertexCount ();
normalOffset += mesh.NormalCount ();
uvOffset += mesh.TextureUVCount ();
}
let objWriter = new OV.TextWriter ();
objWriter.WriteLine (this.GetHeaderText ());
objWriter.WriteArrayLine (['mtllib', mtlFile.GetName ()]);
let vertexOffset = 0;
let normalOffset = 0;
let uvOffset = 0;
let usedMaterialName = null;
for (let meshIndex = 0; meshIndex < model.MeshCount (); meshIndex++) {
let mesh = model.GetMesh (meshIndex);
objWriter.WriteArrayLine (['g', this.GetExportedMeshName (mesh.GetName ())]);
for (let vertexIndex = 0; vertexIndex < mesh.VertexCount (); vertexIndex++) {
let vertex = mesh.GetVertex (vertexIndex);
objWriter.WriteArrayLine (['v', vertex.x, vertex.y, vertex.z]);
}
for (let normalIndex = 0; normalIndex < mesh.NormalCount (); normalIndex++) {
let normal = mesh.GetNormal (normalIndex);
objWriter.WriteArrayLine (['vn', normal.x, normal.y, normal.z]);
}
for (let textureUVIndex = 0; textureUVIndex < mesh.TextureUVCount (); textureUVIndex++) {
let uv = mesh.GetTextureUV (textureUVIndex);
objWriter.WriteArrayLine (['vt', uv.x, uv.y]);
}
for (let triangleIndex = 0; triangleIndex < mesh.TriangleCount (); triangleIndex++) {
let triangle = mesh.GetTriangle (triangleIndex);
let v0 = triangle.v0 + vertexOffset + 1;
let v1 = triangle.v1 + vertexOffset + 1;
let v2 = triangle.v2 + vertexOffset + 1;
let n0 = triangle.n0 + normalOffset + 1;
let n1 = triangle.n1 + normalOffset + 1;
let n2 = triangle.n2 + normalOffset + 1;
if (triangle.mat !== null) {
let material = model.GetMaterial (triangle.mat);
let materialName = this.GetExportedMaterialName (material.name);
if (materialName !== usedMaterialName) {
objWriter.WriteArrayLine (['usemtl', materialName]);
usedMaterialName = materialName;
}
}
let u0 = '';
let u1 = '';
let u2 = '';
if (triangle.HasTextureUVs ()) {
u0 = triangle.u0 + uvOffset + 1;
u1 = triangle.u1 + uvOffset + 1;
u2 = triangle.u2 + uvOffset + 1;
}
objWriter.WriteArrayLine (['f', [v0, u0, n0].join ('/'), [v1, u1, n1].join ('/'), [v2, u2, n2].join ('/')]);
}
vertexOffset += mesh.VertexCount ();
normalOffset += mesh.NormalCount ();
uvOffset += mesh.TextureUVCount ();
}
objFile.SetContent (objWriter.GetText ());
}
objFile.SetContent (objWriter.GetText ());
onFinish ();
}
GetHeaderText ()
{
return '# exported by https://3dviewer.net';
}
GetHeaderText ()
{
return '# exported by https://3dviewer.net';
}
};

View File

@ -10,7 +10,7 @@ OV.ExporterOff = class extends OV.ExporterBase
return format === OV.FileFormat.Text && extension === 'off';
}
ExportContent (model, format, files)
ExportContent (model, format, files, onFinish)
{
let offFile = new OV.ExportedFile ('model.off');
files.push (offFile);
@ -29,5 +29,6 @@ OV.ExporterOff = class extends OV.ExporterBase
});
offFile.SetContent (offWriter.GetText ());
onFinish ();
}
};

View File

@ -10,13 +10,14 @@ OV.ExporterPly = class extends OV.ExporterBase
return (format === OV.FileFormat.Text || format === OV.FileFormat.Binary) && extension === 'ply';
}
ExportContent (model, format, files)
ExportContent (model, format, files, onFinish)
{
if (format === OV.FileFormat.Text) {
this.ExportText (model, files);
} else {
this.ExportBinary (model, files);
}
onFinish ();
}
ExportText (model, files)

View File

@ -10,13 +10,14 @@ OV.ExporterStl = class extends OV.ExporterBase
return (format === OV.FileFormat.Text || format === OV.FileFormat.Binary) && extension === 'stl';
}
ExportContent (model, format, files)
ExportContent (model, format, files, onFinish)
{
if (format === OV.FileFormat.Text) {
this.ExportText (model, files);
} else {
this.ExportBinary (model, files);
}
onFinish ();
}
ExportText (model, files)

96
source/external/rhino.exporter.js vendored Normal file
View File

@ -0,0 +1,96 @@
OV.Exporter3dm = class extends OV.ExporterBase
{
constructor ()
{
super ();
this.rhino = null;
}
CanExport (format, extension)
{
return format === OV.FileFormat.Binary && extension === '3dm';
}
ExportContent (model, format, files, onFinish)
{
if (this.rhino === null) {
let obj = this;
rhino3dm ().then (function (rhino) {
obj.rhino = rhino;
obj.ExportRhinoContent (model, files, onFinish);
});
} else {
this.ExportRhinoContent (model, files, onFinish);
}
}
ExportRhinoContent (model, files, onFinish)
{
function ColorToRhinoColor (color)
{
return {
r : color.r,
g : color.g,
b : color.b,
a : 255
};
}
let rhinoFile = new OV.ExportedFile ('model.3dm');
files.push (rhinoFile);
let rhinoDoc = new this.rhino.File3dm ();
for (let meshIndex = 0; meshIndex < model.MeshCount (); meshIndex++) {
let mesh = model.GetMesh (meshIndex);
let meshBuffer = OV.ConvertMeshToMeshBuffer (mesh);
for (let primitiveIndex = 0; primitiveIndex < meshBuffer.PrimitiveCount (); primitiveIndex++) {
let primitive = meshBuffer.GetPrimitive (primitiveIndex);
let threeJson = {
data : {
attributes : {
position : {
itemSize : 3,
type : 'Float32Array',
array : primitive.vertices
},
normal : {
itemSize : 3,
type : 'Float32Array',
array : primitive.normals
}
},
index : {
type : 'Uint16Array',
array : primitive.indices
}
}
};
let material = model.GetMaterial (primitive.material);
let rhinoMaterial = new this.rhino.Material ();
rhinoMaterial.name = this.GetExportedMaterialName (material.name);
rhinoMaterial.ambientColor = ColorToRhinoColor (material.ambient);
rhinoMaterial.diffuseColor = ColorToRhinoColor (material.diffuse);
rhinoMaterial.specularColor = ColorToRhinoColor (material.specular);
rhinoMaterial.transparency = 1.0 - material.opacity;
let rhinoMaterialIndex = rhinoDoc.materials ().count ();
rhinoDoc.materials ().add (rhinoMaterial);
let rhinoMesh = new this.rhino.Mesh.createFromThreejsJSON (threeJson);
let rhinoAttributes = new this.rhino.ObjectAttributes ();
rhinoAttributes.name = this.GetExportedMeshName (mesh.GetName ());
rhinoAttributes.materialSource = this.rhino.ObjectMaterialSource.MaterialFromObject;
rhinoAttributes.materialIndex = rhinoMaterialIndex;
rhinoDoc.objects ().add (rhinoMesh, rhinoAttributes);
}
}
let writeOptions = new this.rhino.File3dmWriteOptions ();
writeOptions.version = 6;
let rhinoDocBuffer = rhinoDoc.toByteArray (writeOptions);
rhinoFile.SetContent (rhinoDocBuffer);
onFinish ();
}
};

323
source/external/rhino.importer.js vendored Normal file
View File

@ -0,0 +1,323 @@
OV.Importer3dm = class extends OV.ImporterBase
{
constructor ()
{
super ();
this.rhino = null;
}
CanImportExtension (extension)
{
return extension === '3dm';
}
GetKnownFileFormats ()
{
return {
'3dm' : OV.FileFormat.Binary
};
}
GetUpDirection ()
{
return OV.Direction.Z;
}
ClearContent ()
{
this.instanceObjects = null;
this.instanceDefinitions = null;
}
ResetContent ()
{
this.instanceObjects = {};
this.instanceDefinitions = {};
}
ImportContent (fileContent, onFinish)
{
if (this.rhino === null) {
let obj = this;
rhino3dm ().then (function (rhino) {
obj.rhino = rhino;
obj.ImportRhinoContent (fileContent);
onFinish ();
});
} else {
this.ImportRhinoContent (fileContent);
onFinish ();
}
}
ImportRhinoContent (fileContent)
{
let rhinoDoc = this.rhino.File3dm.fromByteArray (fileContent);
if (rhinoDoc === null) {
this.SetError ();
this.SetMessage ('Failed to read Rhino file.');
return;
}
this.ImportRhinoDocument (rhinoDoc);
if (OV.IsModelEmpty (this.model)) {
this.SetError ();
this.SetMessage ('The model doesn\'t contain any 3D meshes. Try to save the model while you are in shaded view in Rhino.');
}
}
ImportRhinoDocument (rhinoDoc)
{
this.InitRhinoInstances (rhinoDoc);
this.ImportRhinoGeometry (rhinoDoc);
}
InitRhinoInstances (rhinoDoc)
{
let rhinoObjects = rhinoDoc.objects ();
for (let i = 0; i < rhinoObjects.count; i++) {
let rhinoObject = rhinoObjects.get (i);
let rhinoAttributes = rhinoObject.attributes ();
if (rhinoAttributes.isInstanceDefinitionObject) {
this.instanceObjects[rhinoAttributes.id] = rhinoObject;
}
}
let rhinoInstanceDefinitions = rhinoDoc.instanceDefinitions ();
for (let i = 0; i < rhinoInstanceDefinitions.count (); i++) {
let rhinoInstanceDefinition = rhinoInstanceDefinitions.get (i);
this.instanceDefinitions[rhinoInstanceDefinition.id] = rhinoInstanceDefinition;
}
}
ImportRhinoGeometry (rhinoDoc)
{
let rhinoObjects = rhinoDoc.objects ();
for (let i = 0; i < rhinoObjects.count; i++) {
let rhinoObject = rhinoObjects.get (i);
this.ImportRhinoGeometryObject (rhinoDoc, rhinoObject, []);
}
}
ImportRhinoGeometryObject (rhinoDoc, rhinoObject, rhinoInstanceReferences)
{
let rhinoGeometry = rhinoObject.geometry ();
let rhinoAttributes = rhinoObject.attributes ();
let objectType = rhinoGeometry.objectType;
if (rhinoAttributes.isInstanceDefinitionObject && rhinoInstanceReferences.length === 0) {
return;
}
let rhinoMesh = null;
let deleteMesh = false;
if (objectType === this.rhino.ObjectType.Mesh) {
rhinoMesh = rhinoGeometry;
deleteMesh = false;
} else if (objectType === this.rhino.ObjectType.Extrusion) {
rhinoMesh = rhinoGeometry.getMesh (this.rhino.MeshType.Any);
deleteMesh = true;
} else if (objectType === this.rhino.ObjectType.Brep) {
rhinoMesh = new this.rhino.Mesh ();
let faces = rhinoGeometry.faces ();
for (let i = 0; i < faces.count; i++) {
let face = faces.get (i);
let mesh = face.getMesh (this.rhino.MeshType.Any);
if (mesh) {
rhinoMesh.append (mesh);
mesh.delete ();
}
face.delete ();
}
faces.delete ();
rhinoMesh.compact ();
deleteMesh = true;
} else if (objectType === this.rhino.ObjectType.SubD) {
rhinoGeometry.subdivide (3);
rhinoMesh = this.rhino.Mesh.createFromSubDControlNet (rhinoGeometry);
deleteMesh = true;
} else if (objectType === this.rhino.ObjectType.InstanceReference) {
let parentDefinitionId = rhinoGeometry.parentIdefId;
let instanceDefinition = this.instanceDefinitions[parentDefinitionId];
if (instanceDefinition !== undefined) {
let instanceObjectIds = instanceDefinition.getObjectIds ();
for (let i = 0; i < instanceObjectIds.length; i++) {
let instanceObjectId = instanceObjectIds[i];
let instanceObject = this.instanceObjects[instanceObjectId];
if (instanceObject !== undefined) {
rhinoInstanceReferences.push (rhinoObject);
this.ImportRhinoGeometryObject (rhinoDoc, instanceObject, rhinoInstanceReferences);
rhinoInstanceReferences.pop ();
}
}
}
}
if (rhinoMesh !== null) {
this.ImportRhinoMesh (rhinoDoc, rhinoMesh, rhinoObject, rhinoInstanceReferences);
if (deleteMesh) {
rhinoMesh.delete ();
}
}
}
ImportRhinoMesh (rhinoDoc, rhinoMesh, rhinoObject, rhinoInstanceReferences)
{
let rhinoAttributes = rhinoObject.attributes ();
let mesh = new OV.Mesh ();
mesh.SetName (rhinoAttributes.name);
let materialIndex = this.GetMaterialIndex (rhinoDoc, rhinoObject, rhinoInstanceReferences);
let threeJson = rhinoMesh.toThreejsJSON ();
let vertices = threeJson.data.attributes.position.array;
for (let i = 0; i < vertices.length; i += 3) {
let x = vertices[i];
let y = vertices[i + 1];
let z = vertices[i + 2];
mesh.AddVertex (new OV.Coord3D (x, y, z));
}
let hasNormals = (threeJson.data.attributes.normal !== undefined);
if (hasNormals) {
let normals = threeJson.data.attributes.normal.array;
for (let i = 0; i < normals.length; i += 3) {
let x = normals[i];
let y = normals[i + 1];
let z = normals[i + 2];
mesh.AddNormal (new OV.Coord3D (x, y, z));
}
}
let hasUVs = (threeJson.data.attributes.uv !== undefined);
if (hasUVs) {
let uvs = threeJson.data.attributes.uv.array;
for (let i = 0; i < uvs.length; i += 2) {
let x = uvs[i];
let y = uvs[i + 1];
mesh.AddTextureUV (new OV.Coord2D (x, y));
}
}
let indices = threeJson.data.index.array;
for (let i = 0; i < indices.length; i += 3) {
let v0 = indices[i];
let v1 = indices[i + 1];
let v2 = indices[i + 2];
let triangle = new OV.Triangle (v0, v1, v2);
if (hasNormals) {
triangle.SetNormals (v0, v1, v2);
}
if (hasUVs) {
triangle.SetTextureUVs (v0, v1, v2);
}
if (materialIndex !== null) {
triangle.SetMaterial (materialIndex);
}
mesh.AddTriangle (triangle);
}
if (rhinoInstanceReferences.length !== 0) {
let matrix = new OV.Matrix ().CreateIdentity ();
for (let i = rhinoInstanceReferences.length - 1; i >= 0; i--) {
let rhinoInstanceReference = rhinoInstanceReferences[i];
let rhinoInstanceReferenceGeometry = rhinoInstanceReference.geometry ();
let rhinoInstanceReferenceMatrix = rhinoInstanceReferenceGeometry.xform.toFloatArray (false);
let transformationMatrix = new OV.Matrix (rhinoInstanceReferenceMatrix);
matrix = matrix.MultiplyMatrix (transformationMatrix);
}
let transformation = new OV.Transformation (matrix);
OV.TransformMesh (mesh, transformation);
}
this.model.AddMesh (mesh);
}
GetMaterialIndex (rhinoDoc, rhinoObject, rhinoInstanceReferences)
{
function GetRhinoMaterial (rhino, rhinoObject, rhinoInstanceReferences)
{
let rhinoAttributes = rhinoObject.attributes ();
if (rhinoAttributes.materialSource === rhino.ObjectMaterialSource.MaterialFromObject) {
let materialIndex = rhinoAttributes.materialIndex;
if (materialIndex > -1) {
return rhinoDoc.materials ().get (materialIndex);
}
} else if (rhinoAttributes.materialSource === rhino.ObjectMaterialSource.MaterialFromLayer) {
let layerIndex = rhinoAttributes.layerIndex;
if (layerIndex > 0) {
let layer = rhinoDoc.layers ().get (layerIndex);
let layerMaterialIndex = layer.renderMaterialIndex;
if (layerMaterialIndex > -1) {
return rhinoDoc.materials ().get (layerMaterialIndex);
}
}
} else if (rhinoAttributes.materialSource === rhino.ObjectMaterialSource.MaterialFromParent) {
if (rhinoInstanceReferences.length !== 0) {
return GetRhinoMaterial (rhino, rhinoInstanceReferences[0], []);
}
}
return null;
}
function FindMatchingMaterial (model, rhinoMaterial)
{
function SetColor (color, rhinoColor)
{
color.Set (rhinoColor.r, rhinoColor.g, rhinoColor.b);
}
function IsBlack (rhinoColor)
{
return rhinoColor.r === 0 && rhinoColor.g === 0 && rhinoColor.b === 0;
}
function IsWhite (rhinoColor)
{
return rhinoColor.r === 255 && rhinoColor.g === 255 && rhinoColor.b === 255;
}
let material = new OV.Material ();
if (rhinoMaterial === null) {
material.diffuse.Set (255, 255, 255);
} else {
material.name = rhinoMaterial.name;
SetColor (material.ambient, rhinoMaterial.ambientColor);
SetColor (material.diffuse, rhinoMaterial.diffuseColor);
SetColor (material.specular, rhinoMaterial.specularColor);
material.opacity = 1.0 - rhinoMaterial.transparency;
material.transparent = OV.IsLower (material.opacity, 1.0);
// material.shininess = rhinoMaterial.shine / 255.0;
if (IsBlack (material.diffuse) && !IsWhite (rhinoMaterial.reflectionColor)) {
SetColor (material.diffuse, rhinoMaterial.reflectionColor);
}
if (IsBlack (material.diffuse) && !IsWhite (rhinoMaterial.transparentColor)) {
SetColor (material.diffuse, rhinoMaterial.transparentColor);
}
}
for (let i = 0; i < model.MaterialCount (); i++) {
let current = model.GetMaterial (i);
if (current.name !== material.name) {
continue;
}
if (!OV.ColorIsEqual (current.ambient, material.ambient)) {
continue;
}
if (!OV.ColorIsEqual (current.diffuse, material.diffuse)) {
continue;
}
if (!OV.ColorIsEqual (current.specular, material.specular)) {
continue;
}
if (!OV.IsEqual (current.opacity, material.opacity)) {
continue;
}
if (current.transparent !== material.transparent) {
continue;
}
if (!OV.IsEqual (current.shininess, material.shininess)) {
continue;
}
return i;
}
return model.AddMaterial (material);
}
let rhinoMaterial = GetRhinoMaterial (this.rhino, rhinoObject, rhinoInstanceReferences);
return FindMatchingMaterial (this.model, rhinoMaterial);
}
};

View File

@ -39,7 +39,7 @@ OV.ConvertModelToThreeMeshes = function (model, callbacks)
color : diffuseColor,
specular : specularColor,
emissive : emissiveColor,
shininess : material.shininess * 10.0,
shininess : material.shininess * 100.0,
opacity : material.opacity,
transparent : material.transparent,
alphaTest : material.alphaTest,

View File

@ -3,6 +3,7 @@ OV.ThreeModelLoader = class
constructor ()
{
this.importer = new OV.Importer ();
this.importer.AddImporter (new OV.Importer3dm ());
this.callbacks = null;
this.inProgress = false;
}
@ -57,10 +58,10 @@ OV.ThreeModelLoader = class
this.callbacks.onImportStart ();
OV.RunTaskAsync (function () {
obj.importer.Import (settings, {
success : function (importResult) {
onSuccess : function (importResult) {
obj.OnModelImported (importResult);
},
error : function (importError) {
onError : function (importError) {
obj.callbacks.onLoadError (importError);
obj.inProgress = false;
}

View File

@ -1,218 +1,218 @@
OV.File = class
{
constructor (file, source)
{
this.source = source;
if (source === OV.FileSource.Url) {
this.fileUrl = file;
this.fileObject = null;
this.name = OV.GetFileName (file);
this.extension = OV.GetFileExtension (file);
} else if (source === OV.FileSource.File) {
this.fileUrl = null;
this.fileObject = file;
this.name = OV.GetFileName (file.name);
this.extension = OV.GetFileExtension (file.name);
}
this.content = null;
}
constructor (file, source)
{
this.source = source;
if (source === OV.FileSource.Url) {
this.fileUrl = file;
this.fileObject = null;
this.name = OV.GetFileName (file);
this.extension = OV.GetFileExtension (file);
} else if (source === OV.FileSource.File) {
this.fileUrl = null;
this.fileObject = file;
this.name = OV.GetFileName (file.name);
this.extension = OV.GetFileExtension (file.name);
}
this.content = null;
}
};
OV.FileList = class
{
constructor (importers)
{
this.files = [];
this.importers = importers;
}
constructor (importers)
{
this.files = [];
this.importers = importers;
}
FillFromFileUrls (fileList)
{
this.Fill (fileList, OV.FileSource.Url);
}
FillFromFileUrls (fileList)
{
this.Fill (fileList, OV.FileSource.Url);
}
FillFromFileObjects (fileList)
{
this.Fill (fileList, OV.FileSource.File);
}
FillFromFileObjects (fileList)
{
this.Fill (fileList, OV.FileSource.File);
}
ExtendFromFileList (files)
{
for (let i = 0; i < files.length; i++) {
let file = files[i];
if (!this.ContainsFileByPath (file.name)) {
this.files.push (file);
}
}
}
ExtendFromFileList (files)
{
for (let i = 0; i < files.length; i++) {
let file = files[i];
if (!this.ContainsFileByPath (file.name)) {
this.files.push (file);
}
}
}
GetFiles ()
{
return this.files;
}
GetFiles ()
{
return this.files;
}
GetContent (onReady)
{
let obj = this;
let taskRunner = new OV.TaskRunner ();
taskRunner.Run (this.files.length, {
runTask : function (index, complete) {
obj.GetFileContent (obj.files[index], complete);
},
onReady : onReady
});
}
GetContent (onReady)
{
let obj = this;
let taskRunner = new OV.TaskRunner ();
taskRunner.Run (this.files.length, {
runTask : function (index, complete) {
obj.GetFileContent (obj.files[index], complete);
},
onReady : onReady
});
}
ContainsFileByPath (filePath)
{
return this.FindFileByPath (filePath) !== null;
}
ContainsFileByPath (filePath)
{
return this.FindFileByPath (filePath) !== null;
}
FindFileByPath (filePath)
{
let fileName = OV.GetFileName (filePath).toLowerCase ();
for (let fileIndex = 0; fileIndex < this.files.length; fileIndex++) {
let file = this.files[fileIndex];
if (file.name.toLowerCase () === fileName) {
return file;
}
}
return null;
}
FindFileByPath (filePath)
{
let fileName = OV.GetFileName (filePath).toLowerCase ();
for (let fileIndex = 0; fileIndex < this.files.length; fileIndex++) {
let file = this.files[fileIndex];
if (file.name.toLowerCase () === fileName) {
return file;
}
}
return null;
}
HasMainFile ()
{
return this.GetMainFile () !== null;
}
HasMainFile ()
{
return this.GetMainFile () !== null;
}
GetMainFile ()
{
for (let fileIndex = 0; fileIndex < this.files.length; fileIndex++) {
let file = this.files[fileIndex];
let importer = this.FindImporter (file);
if (importer !== null) {
return {
file : file,
importer : importer
};
}
}
return null;
}
GetMainFile ()
{
for (let fileIndex = 0; fileIndex < this.files.length; fileIndex++) {
let file = this.files[fileIndex];
let importer = this.FindImporter (file);
if (importer !== null) {
return {
file : file,
importer : importer
};
}
}
return null;
}
IsOnlySource (source)
{
if (this.files.length === 0) {
return false;
}
for (let i = 0; i < this.files.length; i++) {
let file = this.files[i];
if (file.source !== source) {
return false;
}
}
return true;
}
IsOnlySource (source)
{
if (this.files.length === 0) {
return false;
}
for (let i = 0; i < this.files.length; i++) {
let file = this.files[i];
if (file.source !== source) {
return false;
}
}
return true;
}
Fill (fileList, fileSource)
{
this.files = [];
for (let fileIndex = 0; fileIndex < fileList.length; fileIndex++) {
let fileObject = fileList[fileIndex];
let file = new OV.File (fileObject, fileSource);
this.AddFile (file);
}
}
Fill (fileList, fileSource)
{
this.files = [];
for (let fileIndex = 0; fileIndex < fileList.length; fileIndex++) {
let fileObject = fileList[fileIndex];
let file = new OV.File (fileObject, fileSource);
this.AddFile (file);
}
}
AddFile (file)
{
this.files.push (file);
}
GetFileContent (file, complete)
{
let callbacks = {
success : function (content) {
file.content = content;
},
error : function () {
},
complete : function () {
complete ();
}
};
if (file.content !== null) {
complete ();
return;
}
let format = this.GetFileFormat (file);
if (file.source === OV.FileSource.Url) {
OV.RequestUrl (file.fileUrl, format, callbacks);
} else if (file.source === OV.FileSource.File) {
OV.ReadFile (file.fileObject, format, callbacks);
}
}
GetFileFormat (file)
{
for (let importerIndex = 0; importerIndex < this.importers.length; importerIndex++) {
let importer = this.importers[importerIndex];
let extension = file.extension.toLowerCase ();
let knownFormats = importer.GetKnownFileFormats ();
if (knownFormats[extension] !== undefined) {
return knownFormats[extension];
}
}
return OV.FileFormat.Binary;
}
AddFile (file)
{
this.files.push (file);
}
GetFileContent (file, complete)
{
let callbacks = {
success : function (content) {
file.content = content;
},
error : function () {
},
complete : function () {
complete ();
}
};
if (file.content !== null) {
complete ();
return;
}
let format = this.GetFileFormat (file);
if (file.source === OV.FileSource.Url) {
OV.RequestUrl (file.fileUrl, format, callbacks);
} else if (file.source === OV.FileSource.File) {
OV.ReadFile (file.fileObject, format, callbacks);
}
}
GetFileFormat (file)
{
for (let importerIndex = 0; importerIndex < this.importers.length; importerIndex++) {
let importer = this.importers[importerIndex];
let extension = file.extension.toLowerCase ();
let knownFormats = importer.GetKnownFileFormats ();
if (knownFormats[extension] !== undefined) {
return knownFormats[extension];
}
}
return OV.FileFormat.Binary;
}
FindImporter (file)
{
for (let importerIndex = 0; importerIndex < this.importers.length; importerIndex++) {
let importer = this.importers[importerIndex];
if (importer.CanImportExtension (file.extension.toLowerCase ())) {
return importer;
}
}
return null;
}
FindImporter (file)
{
for (let importerIndex = 0; importerIndex < this.importers.length; importerIndex++) {
let importer = this.importers[importerIndex];
if (importer.CanImportExtension (file.extension.toLowerCase ())) {
return importer;
}
}
return null;
}
};
OV.ImportSettings = class
{
constructor ()
{
this.defaultColor = new OV.Color (200, 200, 200);
}
constructor ()
{
this.defaultColor = new OV.Color (200, 200, 200);
}
};
OV.ImportErrorCode =
{
NoImportableFile : 1,
ImportFailed : 2,
UnknownError : 3
NoImportableFile : 1,
ImportFailed : 2,
UnknownError : 3
};
OV.ImportError = class
{
constructor (code, message)
{
this.code = code;
this.message = message;
}
constructor (code, message)
{
this.code = code;
this.message = message;
}
};
OV.ImportResult = class
{
constructor ()
{
this.model = null;
this.mainFile = null;
this.upVector = null;
this.usedFiles = null;
this.missingFiles = null;
}
constructor ()
{
this.model = null;
this.mainFile = null;
this.upVector = null;
this.usedFiles = null;
this.missingFiles = null;
}
};
OV.ImportBuffers = class
@ -257,151 +257,157 @@ OV.ImportBuffers = class
OV.Importer = class
{
constructor ()
constructor ()
{
this.importers = [
new OV.ImporterObj (),
new OV.ImporterStl (),
new OV.ImporterOff (),
new OV.ImporterPly (),
new OV.Importer3ds (),
new OV.ImporterGltf ()
];
this.fileList = new OV.FileList (this.importers);
this.model = null;
this.usedFiles = [];
this.missingFiles = [];
}
AddImporter (importer)
{
this.importers = [
new OV.ImporterObj (),
new OV.ImporterStl (),
new OV.ImporterOff (),
new OV.ImporterPly (),
new OV.Importer3ds (),
new OV.ImporterGltf ()
];
this.fileList = new OV.FileList (this.importers);
this.model = null;
this.usedFiles = [];
this.missingFiles = [];
}
LoadFilesFromUrls (fileList, onReady)
{
this.LoadFiles (fileList, OV.FileSource.Url, onReady);
this.importers.push (importer);
}
LoadFilesFromFileObjects (fileList, onReady)
{
this.LoadFiles (fileList, OV.FileSource.File, onReady);
}
LoadFilesFromUrls (fileList, onReady)
{
this.LoadFiles (fileList, OV.FileSource.Url, onReady);
}
Import (settings, callbacks)
{
let mainFile = this.fileList.GetMainFile ();
if (mainFile === null || mainFile.file === null || mainFile.file.content === null) {
callbacks.error (new OV.ImportError (OV.ImportErrorCode.NoImportableFile, null));
return;
}
LoadFilesFromFileObjects (fileList, onReady)
{
this.LoadFiles (fileList, OV.FileSource.File, onReady);
}
this.RevokeModelUrls ();
this.model = null;
this.usedFiles = [];
this.missingFiles = [];
this.usedFiles.push (mainFile.file.name);
Import (settings, callbacks)
{
let mainFile = this.fileList.GetMainFile ();
if (mainFile === null || mainFile.file === null || mainFile.file.content === null) {
callbacks.onError (new OV.ImportError (OV.ImportErrorCode.NoImportableFile, null));
return;
}
let result = new OV.ImportResult ();
result.mainFile = mainFile.file.name;
this.RevokeModelUrls ();
this.model = null;
this.usedFiles = [];
this.missingFiles = [];
this.usedFiles.push (mainFile.file.name);
let obj = this;
let importer = mainFile.importer;
let buffers = new OV.ImportBuffers (function (fileName) {
let fileBuffer = null;
let file = obj.fileList.FindFileByPath (fileName);
if (file === null || file.content === null) {
obj.missingFiles.push (fileName);
fileBuffer = null;
} else {
fileBuffer = file.content;
obj.usedFiles.push (fileName);
}
return fileBuffer;
});
let obj = this;
let importer = mainFile.importer;
let buffers = new OV.ImportBuffers (function (fileName) {
let fileBuffer = null;
let file = obj.fileList.FindFileByPath (fileName);
if (file === null || file.content === null) {
obj.missingFiles.push (fileName);
fileBuffer = null;
} else {
fileBuffer = file.content;
obj.usedFiles.push (fileName);
}
return fileBuffer;
});
importer.Import (mainFile.file.content, mainFile.file.extension, {
getDefaultMaterial : function () {
let material = new OV.Material ();
material.diffuse = settings.defaultColor;
return material;
},
getFileBuffer : function (filePath) {
return buffers.GetFileBuffer (filePath);
},
getTextureBuffer : function (filePath) {
return buffers.GetTextureBuffer (filePath);
}
});
importer.Import (mainFile.file.content, mainFile.file.extension, {
getDefaultMaterial : function () {
let material = new OV.Material ();
material.diffuse = settings.defaultColor;
return material;
},
getFileBuffer : function (filePath) {
return buffers.GetFileBuffer (filePath);
},
getTextureBuffer : function (filePath) {
return buffers.GetTextureBuffer (filePath);
},
onSuccess : function () {
obj.model = importer.GetModel ();
obj.model.SetName (mainFile.file.name);
let result = new OV.ImportResult ();
result.mainFile = mainFile.file.name;
result.model = obj.model;
result.usedFiles = obj.usedFiles;
result.missingFiles = obj.missingFiles;
result.upVector = importer.GetUpDirection ();
callbacks.onSuccess (result);
},
onError : function () {
let message = importer.GetMessage ();
callbacks.onError (new OV.ImportError (OV.ImportErrorCode.ImportFailed, message));
},
onComplete : function () {
importer.Clear ();
}
});
}
if (importer.IsError ()) {
let message = importer.GetMessage ();
callbacks.error (new OV.ImportError (OV.ImportErrorCode.ImportFailed, message));
return;
}
LoadFiles (fileList, fileSource, onReady)
{
let newFileList = new OV.FileList (this.importers);
if (fileSource === OV.FileSource.Url) {
newFileList.FillFromFileUrls (fileList);
} else if (fileSource === OV.FileSource.File) {
newFileList.FillFromFileObjects (fileList);
}
let reset = false;
if (newFileList.HasMainFile ()) {
reset = true;
} else {
let foundMissingFile = false;
for (let i = 0; i < this.missingFiles.length; i++) {
let missingFile = this.missingFiles[i];
if (newFileList.ContainsFileByPath (missingFile)) {
foundMissingFile = true;
}
}
if (!foundMissingFile) {
reset = true;
} else {
let newFiles = newFileList.GetFiles ();
this.fileList.ExtendFromFileList (newFiles);
reset = false;
}
}
if (reset) {
this.fileList = newFileList;
}
this.fileList.GetContent (function () {
onReady ();
});
}
this.model = importer.GetModel ();
this.model.SetName (mainFile.file.name);
GetFileList ()
{
return this.fileList;
}
result.model = this.model;
result.usedFiles = this.usedFiles;
result.missingFiles = this.missingFiles;
result.upVector = importer.GetUpDirection ();
callbacks.success (result);
}
IsOnlyFileSource (source)
{
return this.fileList.IsOnlySource (source);
}
LoadFiles (fileList, fileSource, onReady)
{
let newFileList = new OV.FileList (this.importers);
if (fileSource === OV.FileSource.Url) {
newFileList.FillFromFileUrls (fileList);
} else if (fileSource === OV.FileSource.File) {
newFileList.FillFromFileObjects (fileList);
}
let reset = false;
if (newFileList.HasMainFile ()) {
reset = true;
} else {
let foundMissingFile = false;
for (let i = 0; i < this.missingFiles.length; i++) {
let missingFile = this.missingFiles[i];
if (newFileList.ContainsFileByPath (missingFile)) {
foundMissingFile = true;
}
}
if (!foundMissingFile) {
reset = true;
} else {
let newFiles = newFileList.GetFiles ();
this.fileList.ExtendFromFileList (newFiles);
reset = false;
}
}
if (reset) {
this.fileList = newFileList;
}
this.fileList.GetContent (function () {
onReady ();
});
}
GetFileList ()
{
return this.fileList;
}
IsOnlyFileSource (source)
{
return this.fileList.IsOnlySource (source);
}
RevokeModelUrls ()
{
if (this.model === null) {
return;
}
for (let i = 0; i < this.model.MaterialCount (); i++) {
let material = this.model.GetMaterial (i);
material.EnumerateTextureMaps (function (texture) {
if (texture.url !== null) {
OV.RevokeObjectUrl (texture.url);
}
});
}
}
RevokeModelUrls ()
{
if (this.model === null) {
return;
}
for (let i = 0; i < this.model.MaterialCount (); i++) {
let material = this.model.GetMaterial (i);
material.EnumerateTextureMaps (function (texture) {
if (texture.url !== null) {
OV.RevokeObjectUrl (texture.url);
}
});
}
}
};

File diff suppressed because it is too large Load Diff

View File

@ -1,57 +1,83 @@
OV.ImporterBase = class
{
constructor ()
{
}
Import (content, extension, callbacks)
{
this.Clear ();
this.extension = extension;
this.callbacks = callbacks;
this.model = new OV.Model ();
this.error = false;
this.message = null;
this.ResetContent ();
let obj = this;
this.ImportContent (content, function () {
obj.CreateResult (callbacks);
});
}
Clear ()
{
this.extension = null;
this.callbacks = null;
this.model = null;
this.error = null;
this.message = null;
this.ClearContent ();
}
Import (content, extension, callbacks)
{
this.extension = extension;
this.callbacks = callbacks;
this.model = new OV.Model ();
this.error = false;
this.message = null;
this.ResetState ();
this.ImportContent (content);
CreateResult (callbacks)
{
if (this.error) {
callbacks.onError ();
callbacks.onComplete ();
return;
}
if (OV.IsModelEmpty (this.model)) {
this.error = true;
callbacks.onError ();
callbacks.onComplete ();
return;
}
OV.FinalizeModel (this.model, this.callbacks.getDefaultMaterial);
}
ResetState ()
{
callbacks.onSuccess ();
callbacks.onComplete ();
}
CanImportExtension (extension)
{
return false;
}
CanImportExtension (extension)
{
return false;
}
GetKnownFileFormats ()
{
return {};
}
GetKnownFileFormats ()
{
return {};
}
GetUpDirection ()
{
return OV.Direction.Z;
}
ImportContent (content)
ClearContent ()
{
}
ResetContent ()
{
}
ImportContent (fileContent, onFinish)
{
}

View File

@ -1,40 +1,40 @@
OV.GltfComponentType =
{
BYTE : 5120,
UNSIGNED_BYTE : 5121,
SHORT : 5122,
UNSIGNED_SHORT : 5123,
UNSIGNED_INT : 5125,
FLOAT : 5126
BYTE : 5120,
UNSIGNED_BYTE : 5121,
SHORT : 5122,
UNSIGNED_SHORT : 5123,
UNSIGNED_INT : 5125,
FLOAT : 5126
};
OV.GltfDataType =
{
SCALAR : 0,
VEC2 : 1,
VEC3 : 2,
VEC4 : 3,
MAT2 : 4,
MAT3 : 5,
SCALAR : 0,
VEC2 : 1,
VEC3 : 2,
VEC4 : 3,
MAT2 : 4,
MAT3 : 5,
MAT4 : 6
};
OV.GltfRenderMode =
{
POINTS : 0,
LINES : 1,
LINE_LOOP : 2,
LINE_STRIP : 3,
TRIANGLES : 4,
TRIANGLE_STRIP : 5,
POINTS : 0,
LINES : 1,
LINE_LOOP : 2,
LINE_STRIP : 3,
TRIANGLES : 4,
TRIANGLE_STRIP : 5,
TRIANGLE_FAN : 6
};
OV.GltfConstants =
{
GLTF_STRING : 0x46546C67,
JSON_CHUNK_TYPE : 0x4E4F534A,
BINARY_CHUNK_TYPE : 0x004E4942
GLTF_STRING : 0x46546C67,
JSON_CHUNK_TYPE : 0x4E4F534A,
BINARY_CHUNK_TYPE : 0x004E4942
};
OV.GltfNodeTree = class
@ -345,49 +345,53 @@ OV.GltfExtensions = class
OV.ImporterGltf = class extends OV.ImporterBase
{
constructor ()
{
super ();
this.bufferContents = null;
this.gltfExtensions = null;
this.imageIndexToTextureParams = null;
}
ResetState ()
{
this.bufferContents = [];
this.gltfExtensions = new OV.GltfExtensions ();
this.imageIndexToTextureParams = {};
}
constructor ()
{
super ();
}
CanImportExtension (extension)
{
return extension === 'gltf' || extension === 'glb';
}
CanImportExtension (extension)
{
return extension === 'gltf' || extension === 'glb';
}
GetKnownFileFormats ()
{
return {
'gltf' : OV.FileFormat.Text,
GetKnownFileFormats ()
{
return {
'gltf' : OV.FileFormat.Text,
'glb' : OV.FileFormat.Binary,
'bin' : OV.FileFormat.Binary
};
}
};
}
GetUpDirection ()
{
return OV.Direction.Y;
}
ImportContent (fileContent)
{
ClearContent ()
{
this.bufferContents = null;
this.gltfExtensions = null;
this.imageIndexToTextureParams = null;
}
ResetContent ()
{
this.bufferContents = [];
this.gltfExtensions = new OV.GltfExtensions ();
this.imageIndexToTextureParams = {};
}
ImportContent (fileContent, onFinish)
{
if (this.extension === 'gltf') {
this.ProcessGltf (fileContent);
} else if (this.extension === 'glb') {
this.ProcessBinaryGltf (fileContent);
}
}
onFinish ();
}
ProcessGltf (fileContent)
{
@ -868,7 +872,7 @@ OV.ImporterGltf = class extends OV.ImporterBase
let reader = new OV.GltfBufferReader (buffer);
reader.SkipBytes (bufferView.byteOffset || 0);
let byteStride = bufferView.byteStride;
if (byteStride !== undefined) {
if (byteStride !== undefined && byteStride !== 0) {
reader.SetByteStride (byteStride);
}

View File

@ -1,387 +1,391 @@
OV.ImporterObj = class extends OV.ImporterBase
{
constructor ()
{
super ();
constructor ()
{
super ();
}
this.globalVertices = null;
this.globalNormals = null;
this.globalUvs = null;
this.currentMesh = null;
this.currentMeshData = null;
this.currentMaterial = null;
this.currentMaterialIndex = null;
this.meshNameToMeshData = null;
this.materialNameToIndex = null;
}
ResetState ()
{
this.globalVertices = [];
this.globalNormals = [];
this.globalUvs = [];
CanImportExtension (extension)
{
return extension === 'obj';
}
GetKnownFileFormats ()
{
return {
'obj' : OV.FileFormat.Text,
'mtl' : OV.FileFormat.Text
};
}
this.currentMesh = null;
this.currentMeshData = null;
this.currentMaterial = null;
this.currentMaterialIndex = null;
this.meshNameToMeshData = {};
this.materialNameToIndex = {};
}
CanImportExtension (extension)
{
return extension === 'obj';
}
GetKnownFileFormats ()
{
return {
'obj' : OV.FileFormat.Text,
'mtl' : OV.FileFormat.Text
};
}
GetUpDirection ()
GetUpDirection ()
{
return OV.Direction.Y;
}
ImportContent (fileContent)
{
let obj = this;
OV.ReadLines (fileContent, function (line) {
if (!obj.IsError ()) {
obj.ProcessLine (line);
}
});
}
ProcessLine (line)
{
if (line[0] === '#') {
return;
}
ClearContent ()
{
this.globalVertices = null;
this.globalNormals = null;
this.globalUvs = null;
this.currentMesh = null;
this.currentMeshData = null;
this.currentMaterial = null;
this.currentMaterialIndex = null;
this.meshNameToMeshData = null;
this.materialNameToIndex = null;
}
let parameters = OV.ParametersFromLine (line, '#');
if (parameters.length === 0) {
return;
}
let keyword = parameters[0].toLowerCase ();
parameters.shift ();
ResetContent ()
{
this.globalVertices = [];
this.globalNormals = [];
this.globalUvs = [];
if (this.ProcessMeshParameter (keyword, parameters, line)) {
return;
}
this.currentMesh = null;
this.currentMeshData = null;
this.currentMaterial = null;
this.currentMaterialIndex = null;
if (this.ProcessMaterialParameter (keyword, parameters, line)) {
return;
}
}
AddNewMesh (name)
{
let meshData = this.meshNameToMeshData[name];
if (meshData === undefined) {
let mesh = new OV.Mesh ();
if (name !== null) {
mesh.SetName (name);
}
this.model.AddMesh (mesh);
meshData = {
mesh : mesh,
data : {
globalToCurrentVertices : {},
globalToCurrentNormals : {},
globalToCurrentUvs : {}
}
};
this.meshNameToMeshData[name] = meshData;
}
this.currentMesh = meshData.mesh;
this.currentMeshData = meshData.data;
}
this.meshNameToMeshData = {};
this.materialNameToIndex = {};
}
ImportContent (fileContent, onFinish)
{
let obj = this;
OV.ReadLines (fileContent, function (line) {
if (!obj.IsError ()) {
obj.ProcessLine (line);
}
});
onFinish ();
}
ProcessLine (line)
{
if (line[0] === '#') {
return;
}
ProcessMeshParameter (keyword, parameters, line)
{
if (keyword === 'g' || keyword === 'o') {
if (parameters.length === 0) {
return true;
}
let name = OV.NameFromLine (line, keyword.length, '#');
this.AddNewMesh (name);
return true;
} else if (keyword === 'v') {
if (parameters.length < 3) {
return true;
}
this.globalVertices.push (new OV.Coord3D (
parseFloat (parameters[0]),
parseFloat (parameters[1]),
parseFloat (parameters[2])
));
return true;
} else if (keyword === 'vn') {
if (parameters.length < 3) {
return true;
}
this.globalNormals.push (new OV.Coord3D (
parseFloat (parameters[0]),
parseFloat (parameters[1]),
parseFloat (parameters[2])
));
return true;
} else if (keyword === 'vt') {
if (parameters.length < 2) {
return true;
}
this.globalUvs.push (new OV.Coord2D (
parseFloat (parameters[0]),
parseFloat (parameters[1])
));
return true;
} else if (keyword === 'f') {
if (parameters.length < 3) {
return true;
}
this.ProcessFace (parameters);
return true;
}
let parameters = OV.ParametersFromLine (line, '#');
if (parameters.length === 0) {
return;
}
let keyword = parameters[0].toLowerCase ();
parameters.shift ();
return false;
}
if (this.ProcessMeshParameter (keyword, parameters, line)) {
return;
}
ProcessMaterialParameter (keyword, parameters, line)
{
function CreateColor (parameters)
{
return new OV.Color (
parseInt (parseFloat (parameters[0] * 255.0), 10),
parseInt (parseFloat (parameters[1] * 255.0), 10),
parseInt (parseFloat (parameters[2] * 255.0), 10)
);
}
if (this.ProcessMaterialParameter (keyword, parameters, line)) {
return;
}
}
AddNewMesh (name)
{
let meshData = this.meshNameToMeshData[name];
if (meshData === undefined) {
let mesh = new OV.Mesh ();
if (name !== null) {
mesh.SetName (name);
}
this.model.AddMesh (mesh);
meshData = {
mesh : mesh,
data : {
globalToCurrentVertices : {},
globalToCurrentNormals : {},
globalToCurrentUvs : {}
}
};
this.meshNameToMeshData[name] = meshData;
}
this.currentMesh = meshData.mesh;
this.currentMeshData = meshData.data;
}
function CreateTexture (keyword, line, callbacks)
{
let texture = new OV.TextureMap ();
let textureName = OV.NameFromLine (line, keyword.length, '#');
let textureBuffer = callbacks.getTextureBuffer (textureName);
texture.name = textureName;
if (textureBuffer !== null) {
texture.url = textureBuffer.url;
texture.buffer = textureBuffer.buffer;
}
return texture;
}
ProcessMeshParameter (keyword, parameters, line)
{
if (keyword === 'g' || keyword === 'o') {
if (parameters.length === 0) {
return true;
}
let name = OV.NameFromLine (line, keyword.length, '#');
this.AddNewMesh (name);
return true;
} else if (keyword === 'v') {
if (parameters.length < 3) {
return true;
}
this.globalVertices.push (new OV.Coord3D (
parseFloat (parameters[0]),
parseFloat (parameters[1]),
parseFloat (parameters[2])
));
return true;
} else if (keyword === 'vn') {
if (parameters.length < 3) {
return true;
}
this.globalNormals.push (new OV.Coord3D (
parseFloat (parameters[0]),
parseFloat (parameters[1]),
parseFloat (parameters[2])
));
return true;
} else if (keyword === 'vt') {
if (parameters.length < 2) {
return true;
}
this.globalUvs.push (new OV.Coord2D (
parseFloat (parameters[0]),
parseFloat (parameters[1])
));
return true;
} else if (keyword === 'f') {
if (parameters.length < 3) {
return true;
}
this.ProcessFace (parameters);
return true;
}
let obj = this;
if (keyword === 'newmtl') {
if (parameters.length === 0) {
return true;
}
let material = new OV.Material ();
let materialName = OV.NameFromLine (line, keyword.length, '#');
let materialIndex = this.model.AddMaterial (material);
material.name = materialName;
this.currentMaterial = material;
this.materialNameToIndex[materialName] = materialIndex;
return true;
} else if (keyword === 'usemtl') {
if (parameters.length === 0) {
return true;
}
let materialName = OV.NameFromLine (line, keyword.length, '#');
let materialIndex = this.materialNameToIndex[materialName];
if (materialIndex !== undefined) {
this.currentMaterialIndex = materialIndex;
}
return true;
} else if (keyword === 'mtllib') {
if (parameters.length === 0) {
return true;
}
let fileName = OV.NameFromLine (line, keyword.length, '#');
let fileBuffer = this.callbacks.getFileBuffer (fileName);
if (fileBuffer !== null) {
OV.ReadLines (fileBuffer, function (line) {
if (!obj.IsError ()) {
obj.ProcessLine (line);
}
});
}
return true;
} else if (keyword === 'map_kd') {
if (this.currentMaterial === null || parameters.length === 0) {
return true;
}
this.currentMaterial.diffuseMap = CreateTexture (keyword, line, this.callbacks);
return true;
} else if (keyword === 'map_ks') {
if (this.currentMaterial === null || parameters.length === 0) {
return true;
}
this.currentMaterial.specularMap = CreateTexture (keyword, line, this.callbacks);
return true;
} else if (keyword === 'map_bump' || keyword === 'bump') {
if (this.currentMaterial === null || parameters.length === 0) {
return true;
}
this.currentMaterial.bumpMap = CreateTexture (keyword, line, this.callbacks);
return true;
} else if (keyword === 'ka') {
if (this.currentMaterial === null || parameters.length < 3) {
return true;
}
this.currentMaterial.ambient = CreateColor (parameters);
return true;
} else if (keyword === 'kd') {
if (this.currentMaterial === null || parameters.length < 3) {
return true;
}
this.currentMaterial.diffuse = CreateColor (parameters);
return true;
} else if (keyword === 'ks') {
if (this.currentMaterial === null || parameters.length < 3) {
return true;
}
this.currentMaterial.specular = CreateColor (parameters);
return true;
} else if (keyword === 'ns') {
if (this.currentMaterial === null || parameters.length < 1) {
return true;
}
this.currentMaterial.shininess = parseFloat (parameters[0]) / 100.0;
return true;
} else if (keyword === 'tr') {
if (this.currentMaterial === null || parameters.length < 1) {
return true;
}
this.currentMaterial.opacity = 1.0 - parseFloat (parameters[0]);
this.currentMaterial.transparent = OV.IsLower (this.currentMaterial.opacity, 1.0);
return true;
} else if (keyword === 'd') {
if (this.currentMaterial === null || parameters.length < 1) {
return true;
}
this.currentMaterial.opacity = parseFloat (parameters[0]);
this.currentMaterial.transparent = OV.IsLower (this.currentMaterial.opacity, 1.0);
return true;
}
return false;
}
return false;
}
ProcessMaterialParameter (keyword, parameters, line)
{
function CreateColor (parameters)
{
return new OV.Color (
parseInt (parseFloat (parameters[0] * 255.0), 10),
parseInt (parseFloat (parameters[1] * 255.0), 10),
parseInt (parseFloat (parameters[2] * 255.0), 10)
);
}
ProcessFace (parameters)
{
function GetRelativeIndex (index, count)
{
if (index > 0) {
return index - 1;
} else {
return count + index;
}
}
function GetLocalIndex (globalValueArray, globalToCurrentIndices, globalIndex, valueAdderFunc)
{
if (isNaN (globalIndex) || globalIndex < 0 || globalIndex >= globalValueArray.length) {
return null;
}
let result = globalToCurrentIndices[globalIndex];
if (result === undefined) {
let globalValue = globalValueArray[globalIndex];
if (globalValue === undefined) {
return null;
}
result = valueAdderFunc (globalValue);
globalToCurrentIndices[globalIndex] = result;
}
return result;
}
function GetLocalVertexIndex (obj, mesh, globalIndex)
{
return GetLocalIndex (obj.globalVertices, obj.currentMeshData.globalToCurrentVertices, globalIndex, function (val) {
return mesh.AddVertex (new OV.Coord3D (val.x, val.y, val.z));
});
}
function GetLocalNormalIndex (obj, mesh, globalIndex)
{
return GetLocalIndex (obj.globalNormals, obj.currentMeshData.globalToCurrentNormals, globalIndex, function (val) {
return mesh.AddNormal (new OV.Coord3D (val.x, val.y, val.z));
});
}
function GetLocalUVIndex (obj, mesh, globalIndex)
{
return GetLocalIndex (obj.globalUvs, obj.currentMeshData.globalToCurrentUvs, globalIndex, function (val) {
return mesh.AddTextureUV (new OV.Coord2D (val.x, val.y));
});
}
let vertices = [];
let normals = [];
let uvs = [];
for (let i = 0; i < parameters.length; i++) {
let vertexParams = parameters[i].split ('/');
vertices.push (GetRelativeIndex (parseInt (vertexParams[0], 10), this.globalVertices.length));
if (vertexParams.length > 1 && vertexParams[1].length > 0) {
uvs.push (GetRelativeIndex (parseInt (vertexParams[1], 10), this.globalUvs.length));
}
if (vertexParams.length > 2 && vertexParams[2].length > 0) {
normals.push (GetRelativeIndex (parseInt (vertexParams[2], 10), this.globalNormals.length));
}
}
if (this.currentMesh === null) {
this.AddNewMesh ('');
}
for (let i = 0; i < vertices.length - 2; i++) {
let v0 = GetLocalVertexIndex (this, this.currentMesh, vertices[0]);
let v1 = GetLocalVertexIndex (this, this.currentMesh, vertices[i + 1]);
let v2 = GetLocalVertexIndex (this, this.currentMesh, vertices[i + 2]);
if (v0 === null || v1 === null || v2 === null) {
this.SetError ();
this.SetMessage ('Invalid vertex index.');
break;
}
let triangle = new OV.Triangle (v0, v1, v2);
if (normals.length === vertices.length) {
let n0 = GetLocalNormalIndex (this, this.currentMesh, normals[0]);
let n1 = GetLocalNormalIndex (this, this.currentMesh, normals[i + 1]);
let n2 = GetLocalNormalIndex (this, this.currentMesh, normals[i + 2]);
if (n0 === null || n1 === null || n2 === null) {
this.SetError ();
this.SetMessage ('Invalid normal index.');
break;
}
triangle.SetNormals (n0, n1, n2);
}
if (uvs.length === vertices.length) {
let u0 = GetLocalUVIndex (this, this.currentMesh, uvs[0]);
let u1 = GetLocalUVIndex (this, this.currentMesh, uvs[i + 1]);
let u2 = GetLocalUVIndex (this, this.currentMesh, uvs[i + 2]);
if (u0 === null || u1 === null || u2 === null) {
this.SetError ();
this.SetMessage ('Invalid uv index.');
break;
}
triangle.SetTextureUVs (u0, u1, u2);
}
if (this.currentMaterialIndex !== null) {
triangle.mat = this.currentMaterialIndex;
}
this.currentMesh.AddTriangle (triangle);
}
}
function CreateTexture (keyword, line, callbacks)
{
let texture = new OV.TextureMap ();
let textureName = OV.NameFromLine (line, keyword.length, '#');
let textureBuffer = callbacks.getTextureBuffer (textureName);
texture.name = textureName;
if (textureBuffer !== null) {
texture.url = textureBuffer.url;
texture.buffer = textureBuffer.buffer;
}
return texture;
}
let obj = this;
if (keyword === 'newmtl') {
if (parameters.length === 0) {
return true;
}
let material = new OV.Material ();
let materialName = OV.NameFromLine (line, keyword.length, '#');
let materialIndex = this.model.AddMaterial (material);
material.name = materialName;
this.currentMaterial = material;
this.materialNameToIndex[materialName] = materialIndex;
return true;
} else if (keyword === 'usemtl') {
if (parameters.length === 0) {
return true;
}
let materialName = OV.NameFromLine (line, keyword.length, '#');
let materialIndex = this.materialNameToIndex[materialName];
if (materialIndex !== undefined) {
this.currentMaterialIndex = materialIndex;
}
return true;
} else if (keyword === 'mtllib') {
if (parameters.length === 0) {
return true;
}
let fileName = OV.NameFromLine (line, keyword.length, '#');
let fileBuffer = this.callbacks.getFileBuffer (fileName);
if (fileBuffer !== null) {
OV.ReadLines (fileBuffer, function (line) {
if (!obj.IsError ()) {
obj.ProcessLine (line);
}
});
}
return true;
} else if (keyword === 'map_kd') {
if (this.currentMaterial === null || parameters.length === 0) {
return true;
}
this.currentMaterial.diffuseMap = CreateTexture (keyword, line, this.callbacks);
return true;
} else if (keyword === 'map_ks') {
if (this.currentMaterial === null || parameters.length === 0) {
return true;
}
this.currentMaterial.specularMap = CreateTexture (keyword, line, this.callbacks);
return true;
} else if (keyword === 'map_bump' || keyword === 'bump') {
if (this.currentMaterial === null || parameters.length === 0) {
return true;
}
this.currentMaterial.bumpMap = CreateTexture (keyword, line, this.callbacks);
return true;
} else if (keyword === 'ka') {
if (this.currentMaterial === null || parameters.length < 3) {
return true;
}
this.currentMaterial.ambient = CreateColor (parameters);
return true;
} else if (keyword === 'kd') {
if (this.currentMaterial === null || parameters.length < 3) {
return true;
}
this.currentMaterial.diffuse = CreateColor (parameters);
return true;
} else if (keyword === 'ks') {
if (this.currentMaterial === null || parameters.length < 3) {
return true;
}
this.currentMaterial.specular = CreateColor (parameters);
return true;
} else if (keyword === 'ns') {
if (this.currentMaterial === null || parameters.length < 1) {
return true;
}
this.currentMaterial.shininess = parseFloat (parameters[0]) / 1000.0;
return true;
} else if (keyword === 'tr') {
if (this.currentMaterial === null || parameters.length < 1) {
return true;
}
this.currentMaterial.opacity = 1.0 - parseFloat (parameters[0]);
this.currentMaterial.transparent = OV.IsLower (this.currentMaterial.opacity, 1.0);
return true;
} else if (keyword === 'd') {
if (this.currentMaterial === null || parameters.length < 1) {
return true;
}
this.currentMaterial.opacity = parseFloat (parameters[0]);
this.currentMaterial.transparent = OV.IsLower (this.currentMaterial.opacity, 1.0);
return true;
}
return false;
}
ProcessFace (parameters)
{
function GetRelativeIndex (index, count)
{
if (index > 0) {
return index - 1;
} else {
return count + index;
}
}
function GetLocalIndex (globalValueArray, globalToCurrentIndices, globalIndex, valueAdderFunc)
{
if (isNaN (globalIndex) || globalIndex < 0 || globalIndex >= globalValueArray.length) {
return null;
}
let result = globalToCurrentIndices[globalIndex];
if (result === undefined) {
let globalValue = globalValueArray[globalIndex];
if (globalValue === undefined) {
return null;
}
result = valueAdderFunc (globalValue);
globalToCurrentIndices[globalIndex] = result;
}
return result;
}
function GetLocalVertexIndex (obj, mesh, globalIndex)
{
return GetLocalIndex (obj.globalVertices, obj.currentMeshData.globalToCurrentVertices, globalIndex, function (val) {
return mesh.AddVertex (new OV.Coord3D (val.x, val.y, val.z));
});
}
function GetLocalNormalIndex (obj, mesh, globalIndex)
{
return GetLocalIndex (obj.globalNormals, obj.currentMeshData.globalToCurrentNormals, globalIndex, function (val) {
return mesh.AddNormal (new OV.Coord3D (val.x, val.y, val.z));
});
}
function GetLocalUVIndex (obj, mesh, globalIndex)
{
return GetLocalIndex (obj.globalUvs, obj.currentMeshData.globalToCurrentUvs, globalIndex, function (val) {
return mesh.AddTextureUV (new OV.Coord2D (val.x, val.y));
});
}
let vertices = [];
let normals = [];
let uvs = [];
for (let i = 0; i < parameters.length; i++) {
let vertexParams = parameters[i].split ('/');
vertices.push (GetRelativeIndex (parseInt (vertexParams[0], 10), this.globalVertices.length));
if (vertexParams.length > 1 && vertexParams[1].length > 0) {
uvs.push (GetRelativeIndex (parseInt (vertexParams[1], 10), this.globalUvs.length));
}
if (vertexParams.length > 2 && vertexParams[2].length > 0) {
normals.push (GetRelativeIndex (parseInt (vertexParams[2], 10), this.globalNormals.length));
}
}
if (this.currentMesh === null) {
this.AddNewMesh ('');
}
for (let i = 0; i < vertices.length - 2; i++) {
let v0 = GetLocalVertexIndex (this, this.currentMesh, vertices[0]);
let v1 = GetLocalVertexIndex (this, this.currentMesh, vertices[i + 1]);
let v2 = GetLocalVertexIndex (this, this.currentMesh, vertices[i + 2]);
if (v0 === null || v1 === null || v2 === null) {
this.SetError ();
this.SetMessage ('Invalid vertex index.');
break;
}
let triangle = new OV.Triangle (v0, v1, v2);
if (normals.length === vertices.length) {
let n0 = GetLocalNormalIndex (this, this.currentMesh, normals[0]);
let n1 = GetLocalNormalIndex (this, this.currentMesh, normals[i + 1]);
let n2 = GetLocalNormalIndex (this, this.currentMesh, normals[i + 2]);
if (n0 === null || n1 === null || n2 === null) {
this.SetError ();
this.SetMessage ('Invalid normal index.');
break;
}
triangle.SetNormals (n0, n1, n2);
}
if (uvs.length === vertices.length) {
let u0 = GetLocalUVIndex (this, this.currentMesh, uvs[0]);
let u1 = GetLocalUVIndex (this, this.currentMesh, uvs[i + 1]);
let u2 = GetLocalUVIndex (this, this.currentMesh, uvs[i + 2]);
if (u0 === null || u1 === null || u2 === null) {
this.SetError ();
this.SetMessage ('Invalid uv index.');
break;
}
triangle.SetTextureUVs (u0, u1, u2);
}
if (this.currentMaterialIndex !== null) {
triangle.mat = this.currentMaterialIndex;
}
this.currentMesh.AddTriangle (triangle);
}
}
};

View File

@ -3,13 +3,34 @@ OV.ImporterOff = class extends OV.ImporterBase
constructor ()
{
super ();
}
CanImportExtension (extension)
{
return extension === 'off';
}
GetKnownFileFormats ()
{
return {
'off' : OV.FileFormat.Text
};
}
GetUpDirection ()
{
return OV.Direction.Y;
}
ClearContent ()
{
this.model = null;
this.mesh = null;
this.status = null;
}
ResetState ()
{
ResetContent ()
{
this.mesh = new OV.Mesh ();
this.model.AddMesh (this.mesh);
this.status = {
@ -18,46 +39,30 @@ OV.ImporterOff = class extends OV.ImporterBase
foundVertex : 0,
foundFace : 0
};
}
CanImportExtension (extension)
{
return extension === 'off';
}
GetKnownFileFormats ()
{
return {
'off' : OV.FileFormat.Text
};
}
GetUpDirection ()
{
return OV.Direction.Y;
}
ImportContent (fileContent)
{
ImportContent (fileContent, onFinish)
{
let obj = this;
OV.ReadLines (fileContent, function (line) {
if (!obj.IsError ()) {
obj.ProcessLine (line);
}
});
}
ProcessLine (line)
{
if (line[0] === '#') {
return;
}
OV.ReadLines (fileContent, function (line) {
if (!obj.IsError ()) {
obj.ProcessLine (line);
}
});
onFinish ();
}
ProcessLine (line)
{
if (line[0] === '#') {
return;
}
let parameters = OV.ParametersFromLine (line, '#');
if (parameters.length === 0) {
return;
}
let parameters = OV.ParametersFromLine (line, '#');
if (parameters.length === 0) {
return;
}
if (parameters[0] === 'OFF') {
return;
}
@ -99,5 +104,5 @@ OV.ImporterOff = class extends OV.ImporterBase
}
return;
}
}
}
};

View File

@ -89,51 +89,55 @@ OV.ImporterPly = class extends OV.ImporterBase
constructor ()
{
super ();
this.model = null;
this.mesh = null;
}
ResetState ()
{
this.mesh = new OV.Mesh ();
this.model.AddMesh (this.mesh);
}
CanImportExtension (extension)
{
return extension === 'ply';
}
CanImportExtension (extension)
{
return extension === 'ply';
}
GetKnownFileFormats ()
{
return {
'ply' : OV.FileFormat.Binary
};
}
{
return {
'ply' : OV.FileFormat.Binary
};
}
GetUpDirection ()
{
return OV.Direction.Y;
}
ClearContent ()
{
this.model = null;
this.mesh = null;
}
ImportContent (fileContent)
{
ResetContent ()
{
this.mesh = new OV.Mesh ();
this.model.AddMesh (this.mesh);
}
ImportContent (fileContent, onFinish)
{
let headerString = this.GetHeaderContent (fileContent);
let header = this.ReadHeader (headerString);
if (!header.Check ()) {
if (header.Check ()) {
if (header.format === 'ascii') {
let contentString = OV.ArrayBufferToUtf8String (fileContent);
contentString = contentString.substr (headerString.length);
this.ReadAsciiContent (header, contentString);
} else if (header.format === 'binary_little_endian' || header.format === 'binary_big_endian') {
this.ReadBinaryContent (header, fileContent, headerString.length);
}
} else {
this.SetError ();
this.SetMessage ('Invalid header information.');
return;
}
if (header.format === 'ascii') {
let contentString = OV.ArrayBufferToUtf8String (fileContent);
contentString = contentString.substr (headerString.length);
this.ReadAsciiContent (header, contentString);
} else if (header.format === 'binary_little_endian' || header.format === 'binary_big_endian') {
this.ReadBinaryContent (header, fileContent, headerString.length);
}
}
onFinish ();
}
GetHeaderContent (fileContent)
{
@ -180,7 +184,7 @@ OV.ImporterPly = class extends OV.ImporterBase
header.AddSingleFormat (parameters[1], parameters[2]);
}
}
});
});
return header;
}
@ -231,7 +235,7 @@ OV.ImporterPly = class extends OV.ImporterBase
}
return;
}
});
});
}
ReadBinaryContent (header, fileContent, headerLength)
@ -279,7 +283,7 @@ OV.ImporterPly = class extends OV.ImporterBase
return null;
}
let materialName = '#' + IntegerToHex (color[0]) + IntegerToHex (color[1]) + IntegerToHex (color[2]) + IntegerToHex (color[3]);
let materialName = 'Color ' + IntegerToHex (color[0]) + IntegerToHex (color[1]) + IntegerToHex (color[2]) + IntegerToHex (color[3]);
let materialIndex = colorToMaterial[materialName];
if (materialIndex === undefined) {
let material = new OV.Material ();

View File

@ -3,36 +3,40 @@ OV.ImporterStl = class extends OV.ImporterBase
constructor ()
{
super ();
this.mesh = null;
this.triangle = null;
}
ResetState ()
{
this.mesh = new OV.Mesh ();
this.model.AddMesh (this.mesh);
this.triangle = null;
}
CanImportExtension (extension)
{
return extension === 'stl';
}
CanImportExtension (extension)
{
return extension === 'stl';
}
GetKnownFileFormats ()
{
return {
'stl' : OV.FileFormat.Binary
};
}
GetKnownFileFormats ()
{
return {
'stl' : OV.FileFormat.Binary
};
}
GetUpDirection ()
{
return OV.Direction.Z;
}
ClearContent ()
{
this.mesh = null;
this.triangle = null;
}
ImportContent (fileContent)
{
ResetContent ()
{
this.mesh = new OV.Mesh ();
this.model.AddMesh (this.mesh);
this.triangle = null;
}
ImportContent (fileContent, onFinish)
{
if (this.IsBinaryStlFile (fileContent)) {
this.ProcessBinary (fileContent);
} else {
@ -44,10 +48,11 @@ OV.ImporterStl = class extends OV.ImporterBase
}
});
}
}
onFinish ();
}
IsBinaryStlFile (fileContent)
{
IsBinaryStlFile (fileContent)
{
let byteLength = fileContent.byteLength;
if (byteLength < 84) {
return false;
@ -64,17 +69,17 @@ OV.ImporterStl = class extends OV.ImporterBase
return true;
}
ProcessLine (line)
{
if (line[0] === '#') {
return;
}
ProcessLine (line)
{
if (line[0] === '#') {
return;
}
let parameters = OV.ParametersFromLine (line, '#');
if (parameters.length === 0) {
return;
}
let parameters = OV.ParametersFromLine (line, '#');
if (parameters.length === 0) {
return;
}
let keyword = parameters[0];
if (keyword === 'solid') {
if (parameters.length > 1) {
@ -132,7 +137,7 @@ OV.ImporterStl = class extends OV.ImporterBase
}
ProcessBinary (fileContent)
{
{
function ReadVector (reader)
{
let coord = new OV.Coord3D ();

View File

@ -40,6 +40,16 @@ OV.MeshBuffer = class
this.primitives = [];
}
PrimitiveCount ()
{
return this.primitives.length;
}
GetPrimitive (index)
{
return this.primitives[index];
}
GetByteLength (indexTypeSize, numberTypeSize)
{
let byteLength = 0;
@ -53,7 +63,7 @@ OV.MeshBuffer = class
OV.ConvertMeshToMeshBuffer = function (mesh)
{
function AddVertexToPrimitiveBuffer (mesh, vertexIndex, normalIndex, uvIndex, primitiveBuffer, primitiveMaps)
function AddVertexToPrimitiveBuffer (mesh, vertexIndex, normalIndex, uvIndex, primitiveBuffer, meshToPrimitiveVertices)
{
function GetUVOrDefault (mesh, uvIndex, forceUVs)
{
@ -106,10 +116,10 @@ OV.ConvertMeshToMeshBuffer = function (mesh)
return null;
}
let primitiveVertices = primitiveMaps.meshToPrimitiveVertices[vertexIndex];
let primitiveVertices = meshToPrimitiveVertices[vertexIndex];
if (primitiveVertices === undefined) {
let primitiveVertex = AddVertex (mesh, vertexIndex, normalIndex, uvIndex, primitiveBuffer);
primitiveMaps.meshToPrimitiveVertices[vertexIndex] = [primitiveVertex];
meshToPrimitiveVertices[vertexIndex] = [primitiveVertex];
} else {
let existingPrimitiveVertex = FindMatchingPrimitiveVertex (mesh, primitiveVertices, normalIndex, uvIndex);
if (existingPrimitiveVertex !== null) {
@ -139,21 +149,19 @@ OV.ConvertMeshToMeshBuffer = function (mesh)
});
let primitiveBuffer = null;
let primitiveMaps = null;
let meshToPrimitiveVertices = null;
for (let i = 0; i < triangleIndices.length; i++) {
let triangleIndex = triangleIndices[i];
let triangle = mesh.GetTriangle (triangleIndex);
if (primitiveBuffer === null || primitiveBuffer.material !== triangle.mat) {
primitiveBuffer = new OV.MeshPrimitiveBuffer ();
primitiveBuffer.material = triangle.mat;
primitiveMaps = {
meshToPrimitiveVertices : {}
};
meshToPrimitiveVertices = {};
meshBuffer.primitives.push (primitiveBuffer);
}
AddVertexToPrimitiveBuffer (mesh, triangle.v0, triangle.n0, triangle.u0, primitiveBuffer, primitiveMaps);
AddVertexToPrimitiveBuffer (mesh, triangle.v1, triangle.n1, triangle.u1, primitiveBuffer, primitiveMaps);
AddVertexToPrimitiveBuffer (mesh, triangle.v2, triangle.n2, triangle.u2, primitiveBuffer, primitiveMaps);
AddVertexToPrimitiveBuffer (mesh, triangle.v0, triangle.n0, triangle.u0, primitiveBuffer, meshToPrimitiveVertices);
AddVertexToPrimitiveBuffer (mesh, triangle.v1, triangle.n1, triangle.u1, primitiveBuffer, meshToPrimitiveVertices);
AddVertexToPrimitiveBuffer (mesh, triangle.v2, triangle.n2, triangle.u2, primitiveBuffer, meshToPrimitiveVertices);
}
return meshBuffer;

View File

@ -25,6 +25,13 @@ OV.Color = class
this.b = b; // 0 .. 255
}
Set (r, g, b)
{
this.r = r;
this.g = g;
this.b = b;
}
Clone ()
{
return new OV.Color (this.r, this.g, this.b);

View File

@ -41,6 +41,16 @@ OV.TransformMesh = function (mesh, transformation)
}
};
OV.FlipMeshTrianglesOrientation = function (mesh)
{
for (let i = 0; i < mesh.TriangleCount (); i++) {
let triangle = mesh.GetTriangle (i);
let tmp = triangle.v1;
triangle.v1 = triangle.v2;
triangle.v2 = tmp;
}
};
OV.GetMeshBoundingBox = function (mesh)
{
let min = new OV.Coord3D (Infinity, Infinity, Infinity);

View File

@ -10,7 +10,6 @@ OV.Init3DViewerElements = function ()
let width = element.clientWidth;
let height = element.clientHeight;
console.log (element.clientHeight);
viewer.Resize (width, height);
let loader = new OV.ThreeModelLoader ();

View File

@ -308,6 +308,10 @@ OV.Navigation = class
}
}
if (newCamera === null) {
return;
}
if (stepCount === 0) {
this.SetCamera (newCamera);
return;

View File

@ -43,7 +43,10 @@ OV.UpVector = class
let newEye = oldCamera.center.Clone ().Offset (defaultDir, distance);
let newCamera = oldCamera.Clone ();
if (this.direction === OV.Direction.Y) {
if (this.direction === OV.Direction.X) {
newCamera.up = new OV.Coord3D (1.0, 0.0, 0.0);
newCamera.eye = newEye;
} if (this.direction === OV.Direction.Y) {
newCamera.up = new OV.Coord3D (0.0, 1.0, 0.0);
newCamera.eye = newEye;
} else if (this.direction === OV.Direction.Z) {
@ -71,6 +74,64 @@ OV.UpVector = class
}
};
OV.ViewerGeometry = class
{
constructor (scene)
{
this.scene = scene;
this.modelMeshes = [];
}
AddModelMeshes (meshes)
{
for (let i = 0; i < meshes.length; i++) {
let mesh = meshes[i];
this.modelMeshes.push (mesh);
this.scene.add (mesh);
}
}
GetModelMeshes ()
{
return this.modelMeshes;
}
ClearModelMeshes ()
{
for (let i = 0; i < this.modelMeshes.length; i++) {
let mesh = this.modelMeshes[i];
mesh.geometry.dispose ();
this.scene.remove (mesh);
}
this.modelMeshes = [];
}
EnumerateModelMeshes (enumerator)
{
for (let i = 0; i < this.modelMeshes.length; i++) {
let mesh = this.modelMeshes[i];
enumerator (mesh);
}
}
GetModelMeshUnderMouse (mouseCoords, camera, width, height)
{
let raycaster = new THREE.Raycaster ();
let mousePos = new THREE.Vector2 ();
mousePos.x = (mouseCoords.x / width) * 2 - 1;
mousePos.y = -(mouseCoords.y / height) * 2 + 1;
raycaster.setFromCamera (mousePos, camera);
let iSectObjects = raycaster.intersectObjects (this.modelMeshes);
for (let i = 0; i < iSectObjects.length; i++) {
let iSectObject = iSectObjects[i];
if (iSectObject.object.type === 'Mesh' && iSectObject.object.visible) {
return iSectObject.object;
}
}
return null;
}
};
OV.Viewer = class
{
constructor ()
@ -78,6 +139,7 @@ OV.Viewer = class
this.canvas = null;
this.renderer = null;
this.scene = null;
this.geometry = null;
this.camera = null;
this.light = null;
this.navigation = null;
@ -101,10 +163,14 @@ OV.Viewer = class
};
this.renderer = new THREE.WebGLRenderer (parameters);
if (window.devicePixelRatio) {
this.renderer.setPixelRatio (window.devicePixelRatio);
}
this.renderer.setClearColor ('#ffffff', 1.0);
this.renderer.setSize (this.canvas.width, this.canvas.height);
this.scene = new THREE.Scene ();
this.geometry = new OV.ViewerGeometry (this.scene);
this.InitCamera ();
this.InitLights ();
@ -136,6 +202,9 @@ OV.Viewer = class
ResizeRenderer (width, height)
{
if (window.devicePixelRatio) {
this.renderer.setPixelRatio (window.devicePixelRatio);
}
this.camera.aspect = width / height;
this.camera.updateProjectionMatrix ();
this.renderer.setSize (width, height);
@ -227,22 +296,19 @@ OV.Viewer = class
AddMeshes (meshes)
{
for (let i = 0; i < meshes.length; i++) {
let mesh = meshes[i];
this.scene.add (mesh);
}
this.geometry.AddModelMeshes (meshes);
this.Render ();
}
Clear ()
{
this.ClearMeshes ();
this.geometry.ClearModelMeshes ();
this.Render ();
}
SetMeshesVisibility (isVisible)
{
this.EnumerateMeshes (function (mesh) {
this.geometry.EnumerateModelMeshes (function (mesh) {
let visible = isVisible (mesh.userData);
if (mesh.visible !== visible) {
mesh.visible = visible;
@ -262,7 +328,7 @@ OV.Viewer = class
return highlightMaterials;
}
this.EnumerateMeshes (function (mesh) {
this.geometry.EnumerateModelMeshes (function (mesh) {
let highlighted = isHighlighted (mesh.userData);
if (highlighted) {
if (mesh.userData.threeMaterials === null) {
@ -279,28 +345,20 @@ OV.Viewer = class
this.Render ();
}
GetMeshUnderMouse (mouseCoords)
GetMeshUserDataUnderMouse (mouseCoords)
{
let raycaster = new THREE.Raycaster ();
let mousePos = new THREE.Vector2 ();
mousePos.x = (mouseCoords.x / this.canvas.width) * 2 - 1;
mousePos.y = -(mouseCoords.y / this.canvas.height) * 2 + 1;
raycaster.setFromCamera (mousePos, this.camera);
let iSectObjects = raycaster.intersectObjects (this.scene.children);
for (let i = 0; i < iSectObjects.length; i++) {
let iSectObject = iSectObjects[i];
if (iSectObject.object.type === 'Mesh' && iSectObject.object.visible) {
return iSectObject.object.userData;
}
let mesh = this.geometry.GetModelMeshUnderMouse (mouseCoords, this.camera, this.canvas.width, this.canvas.height);
if (mesh === null) {
return null;
}
return null;
return mesh.userData;
}
GetBoundingBox (needToProcess)
{
let hasMesh = false;
let boundingBox = new THREE.Box3 ();
this.EnumerateMeshes (function (mesh) {
this.geometry.EnumerateModelMeshes (function (mesh) {
if (needToProcess (mesh.userData)) {
boundingBox.union (new THREE.Box3 ().setFromObject (mesh));
hasMesh = true;
@ -327,31 +385,11 @@ OV.Viewer = class
EnumerateMeshesUserData (enumerator)
{
this.EnumerateMeshes (function (mesh) {
this.geometry.EnumerateModelMeshes (function (mesh) {
enumerator (mesh.userData);
});
}
EnumerateMeshes (enumerator)
{
this.scene.traverse (function (object) {
if (object.isMesh) {
enumerator (object);
}
});
}
ClearMeshes ()
{
for (let i = this.scene.children.length - 1; i >= 0; i--) {
let object = this.scene.children[i];
if (object.isMesh) {
object.geometry.dispose ();
this.scene.remove (object);
}
}
}
InitCamera ()
{
this.camera = new THREE.PerspectiveCamera (45.0, this.canvas.width / this.canvas.height, 0.1, 1000.0);
@ -378,22 +416,29 @@ OV.Viewer = class
this.scene.add (this.light);
}
GetImageSize ()
{
let originalSize = new THREE.Vector2 ();
this.renderer.getSize (originalSize);
return {
width : parseInt (originalSize.x, 10),
height : parseInt (originalSize.y, 10)
};
}
GetImageAsDataUrl (width, height)
{
let originalSize = null;
if (width && height) {
originalSize = new THREE.Vector2 ();
this.renderer.getSize (originalSize);
this.ResizeRenderer (width, height);
let originalSize = this.GetImageSize ();
let renderWidth = width;
let renderHeight = height;
if (window.devicePixelRatio) {
renderWidth /= window.devicePixelRatio;
renderHeight /= window.devicePixelRatio;
}
this.ResizeRenderer (renderWidth, renderHeight);
this.Render ();
let url = this.renderer.domElement.toDataURL ();
if (originalSize !== null) {
this.ResizeRenderer (
parseInt (originalSize.x, 10),
parseInt (originalSize.y, 10)
);
}
this.ResizeRenderer (originalSize.width, originalSize.height);
return url;
}
};

View File

@ -62,308 +62,340 @@ function CreateTestModel ()
return model;
}
describe ('Exporter', function () {
it ('Obj Export', function () {
let model = CreateTestModel ();
let exporter = new OV.Exporter ();
let result = exporter.Export (model, OV.FileFormat.Text, 'obj');
assert.strictEqual (result.length, 5);
let mtlFile = result[0];
assert.strictEqual (mtlFile.GetName (), 'model.mtl');
assert.strictEqual (mtlFile.GetContent (),
[
'# exported by https://3dviewer.net',
'newmtl TestMaterial1',
'Ka 0 0 0',
'Kd 1 0 0',
'Ks 0.2 0.2 0.2',
'Ns 0',
'd 1',
'map_Kd texture1.png',
'map_Ks texture2.png',
'bump texture3.png',
'newmtl TestMaterial2',
'Ka 0 0 0',
'Kd 0 1 0',
'Ks 0.2 0.2 0.2',
'Ns 0',
'd 1',
''
].join ('\n'));
let objFile = result[1];
assert.strictEqual (objFile.GetName (), 'model.obj');
assert.strictEqual (objFile.GetContent (),
[
'# exported by https://3dviewer.net',
'mtllib model.mtl',
'g TestMesh1',
'v 0 0 1',
'v 1 0 1',
'v 0 1 1',
'vn 0 0 1',
'usemtl TestMaterial1',
'f 1//1 2//1 3//1',
'g TestMesh2',
'v 0 0 0',
'v 1 0 0',
'v 0 1 0',
'v -1 0 0',
'v 0 0 1',
'vn 0 0 1',
'vn 0 0 1',
'vn -1 0 0',
'f 4//2 5//2 6//2',
'usemtl TestMaterial2',
'f 4//3 6//3 7//3',
'f 4//4 8//4 6//4',
''
].join ('\n'));
let textureFile1 = result[2];
assert.strictEqual (textureFile1.GetName (), 'texture1.png');
assert.strictEqual (textureFile1.GetContent ().byteLength, 1);
let textureFile2 = result[3];
assert.strictEqual (textureFile2.GetName (), 'texture2.png');
assert.strictEqual (textureFile2.GetContent ().byteLength, 2);
let textureFile3 = result[4];
assert.strictEqual (textureFile3.GetName (), 'texture3.png');
assert.strictEqual (textureFile3.GetContent ().byteLength, 3);
});
it ('Stl Export', function () {
let model = CreateTestModel ();
let exporter = new OV.Exporter ();
let result = exporter.Export (model, OV.FileFormat.Text, 'stl');
assert.strictEqual (result.length, 1);
let stlFile = result[0];
assert.strictEqual (stlFile.GetName (), 'model.stl');
assert.strictEqual (stlFile.GetContent (),
[
'solid Model',
'facet normal 0 0 1',
' outer loop',
' vertex 0 0 1',
' vertex 1 0 1',
' vertex 0 1 1',
' endloop',
'endfacet',
'facet normal 0 0 1',
' outer loop',
' vertex 0 0 0',
' vertex 1 0 0',
' vertex 0 1 0',
' endloop',
'endfacet',
'facet normal 0 0 1',
' outer loop',
' vertex 0 0 0',
' vertex 0 1 0',
' vertex -1 0 0',
' endloop',
'endfacet',
'facet normal -1 0 0',
' outer loop',
' vertex 0 0 0',
' vertex 0 0 1',
' vertex 0 1 0',
' endloop',
'endfacet',
'endsolid Model',
''
].join ('\n'));
});
it ('Stl Binary Export', function () {
let model = CreateTestModel ();
let exporter = new OV.Exporter ();
let result = exporter.Export (model, OV.FileFormat.Binary, 'stl');
assert.strictEqual (result.length, 1);
let stlFile = result[0];
assert.strictEqual (stlFile.GetName (), 'model.stl');
assert.strictEqual (stlFile.GetContent ().byteLength, 284);
let contentBuffer = stlFile.GetContent ();
let importer = new OV.ImporterStl ();
importer.Import (contentBuffer, 'stl', {
getDefaultMaterial () {
return new OV.Material ();
}
});
let importedModel = importer.GetModel ();
assert.strictEqual (importedModel.VertexCount (), 12);
assert.strictEqual (importedModel.TriangleCount (), 4);
});
it ('Off Export', function () {
let model = CreateTestModel ();
let exporter = new OV.Exporter ();
let result = exporter.Export (model, OV.FileFormat.Text, 'off');
assert.strictEqual (result.length, 1);
let offFile = result[0];
assert.strictEqual (offFile.GetName (), 'model.off');
assert.strictEqual (offFile.GetContent (),
[
'OFF',
'8 4 0',
'0 0 1',
'1 0 1',
'0 1 1',
'0 0 0',
'1 0 0',
'0 1 0',
'-1 0 0',
'0 0 1',
'3 0 1 2',
'3 3 4 5',
'3 3 5 6',
'3 3 7 5',
''
].join ('\n'));
});
it ('Ply Export', function () {
let model = CreateTestModel ();
let exporter = new OV.Exporter ();
let result = exporter.Export (model, OV.FileFormat.Text, 'ply');
assert.strictEqual (result.length, 1);
let plyFile = result[0];
assert.strictEqual (plyFile.GetName (), 'model.ply');
assert.strictEqual (plyFile.GetContent (),
[
'ply',
'format ascii 1.0',
'element vertex 8',
'property float x',
'property float y',
'property float z',
'element face 4',
'property list uchar int vertex_index',
'end_header',
'0 0 1',
'1 0 1',
'0 1 1',
'0 0 0',
'1 0 0',
'0 1 0',
'-1 0 0',
'0 0 1',
'3 0 1 2',
'3 3 4 5',
'3 3 5 6',
'3 3 7 5',
''
].join ('\n'));
});
it ('Ply Binary Export', function () {
let model = CreateTestModel ();
let exporter = new OV.Exporter ();
let result = exporter.Export (model, OV.FileFormat.Binary, 'ply');
assert.strictEqual (result.length, 1);
let plyFile = result[0];
assert.strictEqual (plyFile.GetName (), 'model.ply');
assert.strictEqual (plyFile.GetContent ().byteLength, 315);
let contentBuffer = plyFile.GetContent ();
let importer = new OV.ImporterPly ();
importer.Import (contentBuffer, 'ply', {
getDefaultMaterial () {
return new OV.Material ();
}
});
let importedModel = importer.GetModel ();
assert.strictEqual (importedModel.VertexCount (), 8);
assert.strictEqual (importedModel.TriangleCount (), 4);
});
it ('Gltf Ascii Export', function () {
let model = CreateTestModel ();
let exporter = new OV.Exporter ();
let result = exporter.Export (model, OV.FileFormat.Text, 'gltf');
assert.strictEqual (result.length, 3);
let gltfFile = result[0];
let binFile = result[1];
let textureFile = result[2];
assert.strictEqual (gltfFile.GetName (), 'model.gltf');
assert.strictEqual (binFile.GetName (), 'model.bin');
assert.strictEqual (textureFile.GetName (), 'texture1.png');
assert.strictEqual (textureFile.GetContent ().byteLength, 1);
let contentBuffer = gltfFile.GetContent ();
let importer = new OV.ImporterGltf ();
importer.Import (contentBuffer, 'gltf', {
getDefaultMaterial () {
return new OV.Material ();
},
getFileBuffer (filePath) {
if (filePath == 'model.bin') {
return binFile.GetContent ();
}
return null;
},
getTextureBuffer (filePath) {
return null;
}
});
let importedModel = importer.GetModel ();
assert (OV.CheckModel (importedModel));
assert.strictEqual (importedModel.MaterialCount (), 2);
assert.strictEqual (importedModel.MeshCount (), 2);
assert.strictEqual (importedModel.GetMesh (0).GetName (), 'TestMesh1');
assert.strictEqual (importedModel.GetMesh (1).GetName (), 'TestMesh2');
assert.strictEqual (importedModel.VertexCount (), 12);
assert.strictEqual (importedModel.TriangleCount (), 4);
});
it ('Gltf Binary Export', function () {
let model = CreateTestModel ();
function Export (model, format, extension, onReady)
{
let exporter = new OV.Exporter ();
let result = exporter.Export (model, OV.FileFormat.Binary, 'glb');
assert.strictEqual (result.length, 1);
let glbFile = result[0];
assert.strictEqual (glbFile.GetName (), 'model.glb');
let contentBuffer = glbFile.GetContent ();
let importer = new OV.ImporterGltf ();
importer.Import (contentBuffer, 'glb', {
getDefaultMaterial () {
return new OV.Material ();
},
getFileBuffer (filePath) {
return null;
},
getTextureBuffer (filePath) {
return null;
exporter.Export (model, format, extension, {
onSuccess : function (files) {
onReady (files);
}
});
}
let importedModel = importer.GetModel ();
assert (OV.CheckModel (importedModel));
assert.strictEqual (importedModel.MaterialCount (), 2);
assert.strictEqual (importedModel.MeshCount (), 2);
assert.strictEqual (importedModel.GetMesh (0).GetName (), 'TestMesh1');
assert.strictEqual (importedModel.GetMesh (1).GetName (), 'TestMesh2');
assert.strictEqual (importedModel.VertexCount (), 12);
assert.strictEqual (importedModel.TriangleCount (), 4);
});
describe ('Exporter', function () {
it ('Exporter Error', function (done) {
let model = CreateTestModel ();
let exporter = new OV.Exporter ();
exporter.Export (model, OV.FileFormat.Text, 'ext', {
onError : function () {
done ();
}
});
});
it ('Obj Export', function (done) {
let model = CreateTestModel ();
Export (model, OV.FileFormat.Text, 'obj', function (result) {
assert.strictEqual (result.length, 5);
let mtlFile = result[0];
assert.strictEqual (mtlFile.GetName (), 'model.mtl');
assert.strictEqual (mtlFile.GetContent (),
[
'# exported by https://3dviewer.net',
'newmtl TestMaterial1',
'Ka 0 0 0',
'Kd 1 0 0',
'Ks 0.2 0.2 0.2',
'Ns 0',
'd 1',
'map_Kd texture1.png',
'map_Ks texture2.png',
'bump texture3.png',
'newmtl TestMaterial2',
'Ka 0 0 0',
'Kd 0 1 0',
'Ks 0.2 0.2 0.2',
'Ns 0',
'd 1',
''
].join ('\n'));
let objFile = result[1];
assert.strictEqual (objFile.GetName (), 'model.obj');
assert.strictEqual (objFile.GetContent (),
[
'# exported by https://3dviewer.net',
'mtllib model.mtl',
'g TestMesh1',
'v 0 0 1',
'v 1 0 1',
'v 0 1 1',
'vn 0 0 1',
'usemtl TestMaterial1',
'f 1//1 2//1 3//1',
'g TestMesh2',
'v 0 0 0',
'v 1 0 0',
'v 0 1 0',
'v -1 0 0',
'v 0 0 1',
'vn 0 0 1',
'vn 0 0 1',
'vn -1 0 0',
'f 4//2 5//2 6//2',
'usemtl TestMaterial2',
'f 4//3 6//3 7//3',
'f 4//4 8//4 6//4',
''
].join ('\n'));
let textureFile1 = result[2];
assert.strictEqual (textureFile1.GetName (), 'texture1.png');
assert.strictEqual (textureFile1.GetContent ().byteLength, 1);
let textureFile2 = result[3];
assert.strictEqual (textureFile2.GetName (), 'texture2.png');
assert.strictEqual (textureFile2.GetContent ().byteLength, 2);
let textureFile3 = result[4];
assert.strictEqual (textureFile3.GetName (), 'texture3.png');
assert.strictEqual (textureFile3.GetContent ().byteLength, 3);
done ();
});
});
it ('Stl Export', function (done) {
let model = CreateTestModel ();
Export (model, OV.FileFormat.Text, 'stl', function (result) {
assert.strictEqual (result.length, 1);
let stlFile = result[0];
assert.strictEqual (stlFile.GetName (), 'model.stl');
assert.strictEqual (stlFile.GetContent (),
[
'solid Model',
'facet normal 0 0 1',
' outer loop',
' vertex 0 0 1',
' vertex 1 0 1',
' vertex 0 1 1',
' endloop',
'endfacet',
'facet normal 0 0 1',
' outer loop',
' vertex 0 0 0',
' vertex 1 0 0',
' vertex 0 1 0',
' endloop',
'endfacet',
'facet normal 0 0 1',
' outer loop',
' vertex 0 0 0',
' vertex 0 1 0',
' vertex -1 0 0',
' endloop',
'endfacet',
'facet normal -1 0 0',
' outer loop',
' vertex 0 0 0',
' vertex 0 0 1',
' vertex 0 1 0',
' endloop',
'endfacet',
'endsolid Model',
''
].join ('\n'));
done ();
});
});
it ('Stl Binary Export', function (done) {
let model = CreateTestModel ();
Export (model, OV.FileFormat.Binary, 'stl', function (result) {
assert.strictEqual (result.length, 1);
let stlFile = result[0];
assert.strictEqual (stlFile.GetName (), 'model.stl');
assert.strictEqual (stlFile.GetContent ().byteLength, 284);
let contentBuffer = stlFile.GetContent ();
let importer = new OV.ImporterStl ();
importer.Import (contentBuffer, 'stl', {
getDefaultMaterial () {
return new OV.Material ();
},
onSuccess () {
let importedModel = importer.GetModel ();
assert.strictEqual (importedModel.VertexCount (), 12);
assert.strictEqual (importedModel.TriangleCount (), 4);
done ();
}
});
done ();
});
});
it ('Off Export', function (done) {
let model = CreateTestModel ();
Export (model, OV.FileFormat.Text, 'off', function (result) {
assert.strictEqual (result.length, 1);
let offFile = result[0];
assert.strictEqual (offFile.GetName (), 'model.off');
assert.strictEqual (offFile.GetContent (),
[
'OFF',
'8 4 0',
'0 0 1',
'1 0 1',
'0 1 1',
'0 0 0',
'1 0 0',
'0 1 0',
'-1 0 0',
'0 0 1',
'3 0 1 2',
'3 3 4 5',
'3 3 5 6',
'3 3 7 5',
''
].join ('\n'));
done ();
});
});
it ('Ply Export', function (done) {
let model = CreateTestModel ();
Export (model, OV.FileFormat.Text, 'ply', function (result) {
assert.strictEqual (result.length, 1);
let plyFile = result[0];
assert.strictEqual (plyFile.GetName (), 'model.ply');
assert.strictEqual (plyFile.GetContent (),
[
'ply',
'format ascii 1.0',
'element vertex 8',
'property float x',
'property float y',
'property float z',
'element face 4',
'property list uchar int vertex_index',
'end_header',
'0 0 1',
'1 0 1',
'0 1 1',
'0 0 0',
'1 0 0',
'0 1 0',
'-1 0 0',
'0 0 1',
'3 0 1 2',
'3 3 4 5',
'3 3 5 6',
'3 3 7 5',
''
].join ('\n'));
done ();
});
});
it ('Ply Binary Export', function (done) {
let model = CreateTestModel ();
Export (model, OV.FileFormat.Binary, 'ply', function (result) {
assert.strictEqual (result.length, 1);
let plyFile = result[0];
assert.strictEqual (plyFile.GetName (), 'model.ply');
assert.strictEqual (plyFile.GetContent ().byteLength, 315);
let contentBuffer = plyFile.GetContent ();
let importer = new OV.ImporterPly ();
importer.Import (contentBuffer, 'ply', {
getDefaultMaterial () {
return new OV.Material ();
},
onSuccess () {
let importedModel = importer.GetModel ();
assert.strictEqual (importedModel.VertexCount (), 8);
assert.strictEqual (importedModel.TriangleCount (), 4);
done ();
}
});
});
});
it ('Gltf Ascii Export', function (done) {
let model = CreateTestModel ();
Export (model, OV.FileFormat.Text, 'gltf', function (result) {
assert.strictEqual (result.length, 3);
let gltfFile = result[0];
let binFile = result[1];
let textureFile = result[2];
assert.strictEqual (gltfFile.GetName (), 'model.gltf');
assert.strictEqual (binFile.GetName (), 'model.bin');
assert.strictEqual (textureFile.GetName (), 'texture1.png');
assert.strictEqual (textureFile.GetContent ().byteLength, 1);
let contentBuffer = gltfFile.GetContent ();
let importer = new OV.ImporterGltf ();
importer.Import (contentBuffer, 'gltf', {
getDefaultMaterial () {
return new OV.Material ();
},
getFileBuffer (filePath) {
if (filePath == 'model.bin') {
return binFile.GetContent ();
}
return null;
},
getTextureBuffer (filePath) {
return null;
},
onSuccess () {
let importedModel = importer.GetModel ();
assert (OV.CheckModel (importedModel));
assert.strictEqual (importedModel.MaterialCount (), 2);
assert.strictEqual (importedModel.MeshCount (), 2);
assert.strictEqual (importedModel.GetMesh (0).GetName (), 'TestMesh1');
assert.strictEqual (importedModel.GetMesh (1).GetName (), 'TestMesh2');
assert.strictEqual (importedModel.VertexCount (), 12);
assert.strictEqual (importedModel.TriangleCount (), 4);
done ();
}
});
});
});
it ('Gltf Binary Export', function (done) {
let model = CreateTestModel ();
Export (model, OV.FileFormat.Binary, 'glb', function (result) {
assert.strictEqual (result.length, 1);
let glbFile = result[0];
assert.strictEqual (glbFile.GetName (), 'model.glb');
let contentBuffer = glbFile.GetContent ();
let importer = new OV.ImporterGltf ();
importer.Import (contentBuffer, 'glb', {
getDefaultMaterial () {
return new OV.Material ();
},
getFileBuffer (filePath) {
return null;
},
getTextureBuffer (filePath) {
return null;
},
onSuccess () {
let importedModel = importer.GetModel ();
assert (OV.CheckModel (importedModel));
assert.strictEqual (importedModel.MaterialCount (), 2);
assert.strictEqual (importedModel.MeshCount (), 2);
assert.strictEqual (importedModel.GetMesh (0).GetName (), 'TestMesh1');
assert.strictEqual (importedModel.GetMesh (1).GetName (), 'TestMesh2');
assert.strictEqual (importedModel.VertexCount (), 12);
assert.strictEqual (importedModel.TriangleCount (), 4);
done ();
}
});
});
});
});

View File

@ -3,159 +3,167 @@ var testFiles = require ('../utils/testfiles.js');
var testUtils = require ('../utils/testutils.js');
describe ('3ds Importer', function() {
it ('cube_with_materials.obj', function () {
var model = testFiles.Import3dsFile ('cube_with_materials.3ds');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'tex' },
{ name : 'red' },
{ name : 'green' },
{ name : 'blue' },
{ name : 'white' }
],
meshes : [
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
it ('cube_with_materials.3ds', function (done) {
testFiles.Import3dsFile ('cube_with_materials.3ds', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'tex' },
{ name : 'red' },
{ name : 'green' },
{ name : 'blue' },
{ name : 'white' }
],
meshes : [
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
}
}
}
]
]
});
done ();
});
});
it ('cube_with_texture_transformations.3ds', function () {
var model = testFiles.Import3dsFile ('cube_with_texture_transformations.3ds');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'tex' },
{ name : 'red' },
{ name : 'green' },
{ name : 'blue' },
{ name : 'white' }
],
meshes : [
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
it ('cube_with_texture_transformations.3ds', function (done) {
testFiles.Import3dsFile ('cube_with_texture_transformations.3ds', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'tex' },
{ name : 'red' },
{ name : 'green' },
{ name : 'blue' },
{ name : 'white' }
],
meshes : [
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
}
}
}
]
]
});
done ();
});
});
it ('cube_two_instances.3ds', function () {
var model = testFiles.Import3dsFile ('cube_two_instances.3ds');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'tex' },
{ name : 'red' },
{ name : 'green' },
{ name : 'blue' },
{ name : 'white' }
],
meshes : [
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
}
},
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [2, 0, 0],
max : [3, 1, 1]
}
}
]
it ('cube_two_instances.3ds', function (done) {
testFiles.Import3dsFile ('cube_two_instances.3ds', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'tex' },
{ name : 'red' },
{ name : 'green' },
{ name : 'blue' },
{ name : 'white' }
],
meshes : [
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
}
},
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [2, 0, 0],
max : [3, 1, 1]
}
}
]
});
done ();
});
});
it ('cube_four_instances.3ds', function () {
var model = testFiles.Import3dsFile ('cube_four_instances.3ds');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'tex' },
{ name : 'red' },
{ name : 'green' },
{ name : 'blue' },
{ name : 'white' }
],
meshes : [
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
}
},
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [2, 0, 0],
max : [3, 1, 1]
}
},
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [2, 2, 0],
max : [3, 3, 1]
}
},
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [0, 2, 0],
max : [1, 3, 1]
}
}
]
it ('cube_four_instances.3ds', function (done) {
testFiles.Import3dsFile ('cube_four_instances.3ds', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'tex' },
{ name : 'red' },
{ name : 'green' },
{ name : 'blue' },
{ name : 'white' }
],
meshes : [
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
}
},
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [2, 0, 0],
max : [3, 1, 1]
}
},
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [2, 2, 0],
max : [3, 3, 1]
}
},
{
name : 'cube',
vertexCount : 8,
normalCount : 12,
uvCount : 8,
triangleCount : 12,
boundingBox : {
min : [0, 2, 0],
max : [1, 3, 1]
}
}
]
});
done ();
});
});
});

View File

@ -6,10 +6,10 @@ function ImportFilesWithImporter (importer, files, callbacks)
importer.LoadFilesFromFileObjects (files, function () {
let settings = new OV.ImportSettings ();
importer.Import (settings, {
success : function (importResult) {
onSuccess : function (importResult) {
callbacks.success (importer, importResult);
},
error : function (importError) {
onError : function (importError) {
callbacks.error (importer, importError);
}
});
@ -23,7 +23,7 @@ function ImportFiles (files, callbacks)
}
describe ('Importer Test', function () {
it ('Empty File List', function () {
it ('Empty File List', function (done) {
let files = [];
ImportFiles (files, {
success : function (importer, importResult) {
@ -31,11 +31,12 @@ describe ('Importer Test', function () {
},
error : function (importer, importError) {
assert.strictEqual (importError.code, OV.ImportErrorCode.NoImportableFile);
done ();
}
});
});
it ('Not existing file', function () {
it ('Not existing file', function (done) {
let files = [
new FileObject ('obj', 'missing.obj')
];
@ -45,11 +46,12 @@ describe ('Importer Test', function () {
},
error : function (importer, importError) {
assert.strictEqual (importError.code, OV.ImportErrorCode.NoImportableFile);
done ();
}
});
});
it ('Not imprtable file', function () {
it ('Not imprtable file', function (done) {
let files = [
new FileObject ('', 'wrong.ext')
];
@ -59,11 +61,12 @@ describe ('Importer Test', function () {
},
error : function (importer, importError) {
assert.strictEqual (importError.code, OV.ImportErrorCode.NoImportableFile);
done ();
}
});
});
it ('Wrong file', function () {
it ('Wrong file', function (done) {
let files = [
new FileObject ('3ds', 'wrong.3ds')
];
@ -73,11 +76,12 @@ describe ('Importer Test', function () {
},
error : function (importer, importError) {
assert.strictEqual (importError.code, OV.ImportErrorCode.ImportFailed);
done ();
}
});
});
it ('Single file', function () {
it ('Single file', function (done) {
let files = [
new FileObject ('obj', 'single_triangle.obj')
];
@ -86,6 +90,7 @@ describe ('Importer Test', function () {
assert (!OV.IsModelEmpty (importResult.model));
assert.deepStrictEqual (importResult.usedFiles, ['single_triangle.obj']);
assert.deepStrictEqual (importResult.missingFiles, []);
done ();
},
error : function (importer, importError) {
assert.fail ();
@ -93,7 +98,7 @@ describe ('Importer Test', function () {
});
});
it ('Multiple files', function () {
it ('Multiple files', function (done) {
let files = [
new FileObject ('obj', 'cube_with_materials.obj'),
new FileObject ('obj', 'cube_with_materials.mtl'),
@ -105,7 +110,8 @@ describe ('Importer Test', function () {
success : function (importer, importResult) {
assert (!OV.IsModelEmpty (importResult.model));
assert.deepStrictEqual (importResult.usedFiles, ['cube_with_materials.obj', 'cube_with_materials.mtl', 'cube_texture.png']);
assert.deepStrictEqual (importResult.missingFiles, []);
assert.deepStrictEqual (importResult.missingFiles, []);
done ();
},
error : function (importer, importError) {
assert.fail ();
@ -113,7 +119,7 @@ describe ('Importer Test', function () {
});
});
it ('Missing files', function () {
it ('Missing files', function (done) {
let files = [];
files.push (new FileObject ('obj', 'cube_with_materials.obj'));
ImportFiles (files, {
@ -121,36 +127,38 @@ describe ('Importer Test', function () {
assert (!OV.IsModelEmpty (importResult.model));
assert.deepStrictEqual (importResult.usedFiles, ['cube_with_materials.obj']);
assert.deepStrictEqual (importResult.missingFiles, ['cube_with_materials.mtl']);
files.push (new FileObject ('obj', 'cube_with_materials.mtl'));
ImportFiles (files, {
success : function (importer, importResult) {
assert (!OV.IsModelEmpty (importResult.model));
assert.deepStrictEqual (importResult.usedFiles, ['cube_with_materials.obj', 'cube_with_materials.mtl']);
assert.deepStrictEqual (importResult.missingFiles, ['cube_texture.png']);
files.push (new FileObject ('obj', 'cube_texture.png'));
ImportFiles (files, {
success : function (importer, importResult) {
assert (!OV.IsModelEmpty (importResult.model));
assert.deepStrictEqual (importResult.usedFiles, ['cube_with_materials.obj', 'cube_with_materials.mtl', 'cube_texture.png']);
assert.deepStrictEqual (importResult.missingFiles, []);
done ();
},
error : function (importer, importError) {
assert.fail ();
}
});
},
error : function (importer, importError) {
assert.fail ();
}
});
},
error : function (importer, importError) {
assert.fail ();
}
});
files.push (new FileObject ('obj', 'cube_with_materials.mtl'));
ImportFiles (files, {
success : function (importer, importResult) {
assert (!OV.IsModelEmpty (importResult.model));
assert.deepStrictEqual (importResult.usedFiles, ['cube_with_materials.obj', 'cube_with_materials.mtl']);
assert.deepStrictEqual (importResult.missingFiles, ['cube_texture.png']);
},
error : function (importer, importError) {
assert.fail ();
}
});
files.push (new FileObject ('obj', 'cube_texture.png'));
ImportFiles (files, {
success : function (importer, importResult) {
assert (!OV.IsModelEmpty (importResult.model));
assert.deepStrictEqual (importResult.usedFiles, ['cube_with_materials.obj', 'cube_with_materials.mtl', 'cube_texture.png']);
assert.deepStrictEqual (importResult.missingFiles, []);
},
error : function (importer, importError) {
assert.fail ();
}
});
});
it ('Missing texture multiple times', function () {
it ('Missing texture multiple times', function (done) {
let files = [
new FileObject ('obj', 'two_materials_same_texture.obj'),
new FileObject ('obj', 'two_materials_same_texture.mtl'),
@ -160,6 +168,7 @@ describe ('Importer Test', function () {
assert (!OV.IsModelEmpty (importResult.model));
assert.deepStrictEqual (importResult.usedFiles, ['two_materials_same_texture.obj', 'two_materials_same_texture.mtl']);
assert.deepStrictEqual (importResult.missingFiles, ['texture.png']);
done ();
},
error : function (importer, importError) {
assert.fail ();
@ -167,7 +176,7 @@ describe ('Importer Test', function () {
});
});
it ('Append Missing files', function () {
it ('Append Missing files', function (done) {
let theImporter = new OV.Importer ();
ImportFilesWithImporter (theImporter, [new FileObject ('obj', 'cube_with_materials.obj')], {
success : function (importer, importResult) {
@ -184,6 +193,7 @@ describe ('Importer Test', function () {
assert (!OV.IsModelEmpty (importResult.model));
assert.deepStrictEqual (importResult.usedFiles, ['cube_with_materials.obj', 'cube_with_materials.mtl', 'cube_texture.png']);
assert.deepStrictEqual (importResult.missingFiles, []);
done ();
},
error : function (importer, importError) {
assert.fail ();
@ -201,7 +211,7 @@ describe ('Importer Test', function () {
});
});
it ('Reuse importer', function () {
it ('Reuse importer', function (done) {
let files1 = [
new FileObject ('obj', 'cube_with_materials.obj'),
new FileObject ('obj', 'cube_with_materials.mtl'),
@ -223,6 +233,7 @@ describe ('Importer Test', function () {
assert (!OV.IsModelEmpty (importResult.model));
assert.deepStrictEqual (importResult.usedFiles, ['single_triangle.obj']);
assert.deepStrictEqual (importResult.missingFiles, []);
done ();
},
error : function (importer, importError) {
assert.fail ();
@ -235,7 +246,7 @@ describe ('Importer Test', function () {
});
});
it ('Default color', function () {
it ('Default color', function (done) {
let files = [
new FileObject ('stl', 'single_triangle.stl')
];
@ -244,14 +255,15 @@ describe ('Importer Test', function () {
let settings = new OV.ImportSettings ();
settings.defaultColor = new OV.Color (200, 0, 0);
theImporter.Import (settings, {
success : function (importResult) {
onSuccess : function (importResult) {
assert (!OV.IsModelEmpty (importResult.model));
assert.deepStrictEqual (importResult.usedFiles, ['single_triangle.stl']);
assert.deepStrictEqual (importResult.missingFiles, []);
let material = importResult.model.GetMaterial (0);
assert.deepStrictEqual (material.diffuse, new OV.Color (200, 0, 0));
done ();
},
error : function (importError) {
onError : function (importError) {
assert.fail ();
}
});

View File

@ -6,348 +6,384 @@ let testUtils = require ('../utils/testutils.js');
//console.log (util.inspect(testUtils.ModelToObjectSimple (model), {showHidden: false, depth: null}))
describe ('Gltf Importer', function () {
it ('Triangle', function () {
it ('Triangle', function (done) {
let testFileList = [
['Triangle/glTF', 'Triangle.gltf'],
['Triangle/glTF-Embedded', 'Triangle.gltf'],
['TriangleWithoutIndices/glTF', 'TriangleWithoutIndices.gltf'],
['TriangleWithoutIndices/glTF-Embedded', 'TriangleWithoutIndices.gltf']
];
let processed = 0;
for (let i = 0; i < testFileList.length; i++) {
let testFile = testFileList[i];
let model = testFiles.ImportGltfFile (testFile[0], testFile[1]);
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 3,
normalCount : 1,
uvCount : 0,
triangleCount : 1,
boundingBox : {
min : [0.0, 0.0, 0.0],
max : [1.0, 1.0, 0.0]
testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 3,
normalCount : 1,
uvCount : 0,
triangleCount : 1,
boundingBox : {
min : [0.0, 0.0, 0.0],
max : [1.0, 1.0, 0.0]
}
}
}
]
});
]
});
processed += 1;
if (processed == testFileList.length) {
done ();
}
});
}
});
it ('Box', function () {
it ('Box', function (done) {
let testFileList = [
['Box/glTF', 'Box.gltf'],
['Box/glTF-Embedded', 'Box.gltf'],
['Box/glTF-Binary', 'Box.glb']
];
let processed = 0;
for (let i = 0; i < testFileList.length; i++) {
let testFile = testFileList[i];
let model = testFiles.ImportGltfFile (testFile[0], testFile[1]);
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'Red' }
],
meshes : [
{
name : 'Mesh',
vertexCount : 24,
normalCount : 24,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [-0.5, -0.5, -0.5],
max : [0.5, 0.5, 0.5]
testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'Red' }
],
meshes : [
{
name : 'Mesh',
vertexCount : 24,
normalCount : 24,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [-0.5, -0.5, -0.5],
max : [0.5, 0.5, 0.5]
}
}
}
]
});
]
});
processed += 1;
if (processed == testFileList.length) {
done ();
}
});
}
});
it ('BoxInterleaved', function () {
it ('BoxInterleaved', function (done) {
let testFileList = [
['BoxInterleaved/glTF', 'BoxInterleaved.gltf'],
['BoxInterleaved/glTF-Embedded', 'BoxInterleaved.gltf'],
['BoxInterleaved/glTF-Binary', 'BoxInterleaved.glb']
];
let processed = 0;
for (let i = 0; i < testFileList.length; i++) {
let testFile = testFileList[i];
let model = testFiles.ImportGltfFile (testFile[0], testFile[1]);
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : 'Mesh',
vertexCount : 24,
normalCount : 24,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [-0.5, -0.5, -0.5],
max : [0.5, 0.5, 0.5]
testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : 'Mesh',
vertexCount : 24,
normalCount : 24,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [-0.5, -0.5, -0.5],
max : [0.5, 0.5, 0.5]
}
}
}
]
});
]
});
processed += 1;
if (processed == testFileList.length) {
done ();
}
});
}
});
it ('BoxTextured', function () {
it ('BoxTextured', function (done) {
let testFileList = [
['BoxTextured/glTF', 'BoxTextured.gltf'],
['BoxTextured/glTF-Embedded', 'BoxTextured.gltf'],
['BoxTextured/glTF-Binary', 'BoxTextured.glb']
];
let processed = 0;
for (let i = 0; i < testFileList.length; i++) {
let testFile = testFileList[i];
let model = testFiles.ImportGltfFile (testFile[0], testFile[1]);
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'Texture' }
],
meshes : [
{
name : 'Mesh',
vertexCount : 24,
normalCount : 24,
uvCount : 24,
triangleCount : 12,
boundingBox : {
min : [-0.5, -0.5, -0.5],
max : [0.5, 0.5, 0.5]
testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'Texture' }
],
meshes : [
{
name : 'Mesh',
vertexCount : 24,
normalCount : 24,
uvCount : 24,
triangleCount : 12,
boundingBox : {
min : [-0.5, -0.5, -0.5],
max : [0.5, 0.5, 0.5]
}
}
}
]
});
]
});
processed += 1;
if (processed == testFileList.length) {
done ();
}
});
}
});
it ('SimpleMeshes', function () {
it ('SimpleMeshes', function (done) {
let testFileList = [
['SimpleMeshes/glTF', 'SimpleMeshes.gltf'],
['SimpleMeshes/glTF-Embedded', 'SimpleMeshes.gltf']
];
let processed = 0;
for (let i = 0; i < testFileList.length; i++) {
let testFile = testFileList[i];
let model = testFiles.ImportGltfFile (testFile[0], testFile[1]);
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 3,
normalCount : 3,
uvCount : 0,
triangleCount : 1,
boundingBox : {
min : [0.0, 0.0, 0.0],
max : [1.0, 1.0, 0.0]
testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 3,
normalCount : 3,
uvCount : 0,
triangleCount : 1,
boundingBox : {
min : [0.0, 0.0, 0.0],
max : [1.0, 1.0, 0.0]
}
},
{
name : '',
vertexCount : 3,
normalCount : 3,
uvCount : 0,
triangleCount : 1,
boundingBox : {
min : [1.0, 0.0, 0.0],
max : [2.0, 1.0, 0.0]
}
}
},
{
name : '',
vertexCount : 3,
normalCount : 3,
uvCount : 0,
triangleCount : 1,
boundingBox : {
min : [1.0, 0.0, 0.0],
max : [2.0, 1.0, 0.0]
}
}
]
});
]
});
processed += 1;
if (processed == testFileList.length) {
done ();
}
});
}
});
it ('OrientationTest', function () {
it ('OrientationTest', function (done) {
let testFileList = [
['OrientationTest/glTF', 'OrientationTest.gltf'],
['OrientationTest/glTF-Embedded', 'OrientationTest.gltf'],
['OrientationTest/glTF-Binary', 'OrientationTest.glb'],
];
let processed = 0;
for (let i = 0; i < testFileList.length; i++) {
let testFile = testFileList[i];
let model = testFiles.ImportGltfFile (testFile[0], testFile[1]);
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'BaseMaterial' },
{ name : 'MatX1' },
{ name : 'MatX2' },
{ name : 'MatY1' },
{ name : 'MatY2' },
{ name : 'MatZ1' },
{ name : 'MatZ2' }
],
meshes : [
{
name: 'ArrowMeshZ2',
vertexCount: 78,
normalCount: 78,
uvCount: 0,
triangleCount: 38,
boundingBox : {
min: [ -0.6921195564310951, -1.0785199551363698, -5.330651201963446 ],
max: [ 1.0439303242310798, 2.868914373727357, -4.66934876823423 ]
testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'BaseMaterial' },
{ name : 'MatX1' },
{ name : 'MatX2' },
{ name : 'MatY1' },
{ name : 'MatY2' },
{ name : 'MatZ1' },
{ name : 'MatZ2' }
],
meshes : [
{
name: 'ArrowMeshZ2',
vertexCount: 78,
normalCount: 78,
uvCount: 0,
triangleCount: 38,
boundingBox : {
min: [ -0.6921195564310951, -1.0785199551363698, -5.330651201963446 ],
max: [ 1.0439303242310798, 2.868914373727357, -4.66934876823423 ]
}
},
{
name: 'TargetMeshZ2',
vertexCount: 50,
normalCount: 50,
uvCount: 0,
triangleCount: 26,
boundingBox : {
min: [ 0.8097413778305054, 2.8717148303985596, -5.33065128326416 ],
max: [ 1.4936277866363525, 3.9211390018463135, -4.66934871673584 ]
}
},
{
name: 'TargetMeshY2',
vertexCount: 50,
normalCount: 50,
uvCount: 0,
triangleCount: 26,
boundingBox : {
min: [ -1.1686336994171143, -5.330650806427002, 2.93727445602417 ],
max: [ -0.46912679076194763, -4.66934871673584, 3.9916374683380127 ]
}
},
{
name: 'ArrowMeshY2',
vertexCount: 78,
normalCount: 78,
uvCount: 0,
triangleCount: 38,
boundingBox : {
min: [ -0.9557393651589479, -5.330651177643153, -1.06505742884149 ],
max: [ 0.6167901044859734, -4.6693486435429055, 2.934442924096579 ]
}
},
{
name: 'ArrowMeshX2',
vertexCount: 78,
normalCount: 78,
uvCount: 0,
triangleCount: 38,
boundingBox : {
min: [ -5.330651171390089, -1.0326269494863676, -0.6059335185163844 ],
max: [ -4.669348828609911, 2.9885841671721116, 0.8202131194767724 ]
}
},
{
name: 'TargetMeshX2',
vertexCount: 54,
normalCount: 54,
uvCount: 0,
triangleCount: 26,
boundingBox : {
min: [ -5.33065128326416, 2.991360902786255, -0.012430161237716675 ],
max: [ -4.66934871673584, 4.039160251617432, 0.6999828815460205 ]
}
},
{
name: 'TargetMeshZ1',
vertexCount: 52,
normalCount: 52,
uvCount: 0,
triangleCount: 26,
boundingBox : {
min: [ -1.3648574352264404, 2.9005930423736572, 4.66934871673584 ],
max: [ -0.6740907430648804, 3.9529545307159424, 5.33065128326416 ]
}
},
{
name: 'ArrowMeshZ1',
vertexCount: 74,
normalCount: 74,
uvCount: 0,
triangleCount: 38,
boundingBox : {
min: [ -1.009571011381568, -1.074115497823536, 4.669348895549774 ],
max: [ 0.6625885973069405, 2.8977772707193465, 5.330651104450226 ]
}
},
{
name: 'TargetMeshX1',
vertexCount: 54,
normalCount: 54,
uvCount: 0,
triangleCount: 26,
boundingBox : {
min: [ 4.66934871673584, 2.4595587253570557, -2.553251266479492 ],
max: [ 5.33065128326416, 3.432579517364502, -1.7226401567459106 ]
}
},
{
name: 'ArrowMeshX1',
vertexCount: 78,
normalCount: 78,
uvCount: 0,
triangleCount: 38,
boundingBox : {
min: [ 4.669348835945129, -1.0589144181932033, -1.7207290818192755 ],
max: [ 5.330651164054871, 2.4574561383341145, 0.9159925616542917 ]
}
},
{
name: 'TargetMeshY1',
vertexCount: 52,
normalCount: 52,
uvCount: 0,
triangleCount: 26,
boundingBox : {
min: [ 2.8218495845794678, 4.669349193572998, -1.6833229064941406 ],
max: [ 3.864471435546875, 5.33065128326416, -1.0113166570663452 ]
}
},
{
name: 'ArrowMeshY1',
vertexCount: 78,
normalCount: 78,
uvCount: 0,
triangleCount: 38,
boundingBox : {
min: [ -1.0826615032554154, 4.669348806142807, -1.093071740019906 ],
max: [ 2.8190779754834807, 5.3306513130664825, 0.7348238365226794 ]
}
},
{
name: 'BaseCubeMesh',
vertexCount: 272,
normalCount: 272,
uvCount: 0,
triangleCount: 140,
boundingBox : {
min: [ -5.000001907348633, -5, -5.000001907348633 ],
max: [ 5.000002384185791, 5, 5.000002861022949 ]
}
}
},
{
name: 'TargetMeshZ2',
vertexCount: 50,
normalCount: 50,
uvCount: 0,
triangleCount: 26,
boundingBox : {
min: [ 0.8097413778305054, 2.8717148303985596, -5.33065128326416 ],
max: [ 1.4936277866363525, 3.9211390018463135, -4.66934871673584 ]
}
},
{
name: 'TargetMeshY2',
vertexCount: 50,
normalCount: 50,
uvCount: 0,
triangleCount: 26,
boundingBox : {
min: [ -1.1686336994171143, -5.330650806427002, 2.93727445602417 ],
max: [ -0.46912679076194763, -4.66934871673584, 3.9916374683380127 ]
}
},
{
name: 'ArrowMeshY2',
vertexCount: 78,
normalCount: 78,
uvCount: 0,
triangleCount: 38,
boundingBox : {
min: [ -0.9557393651589479, -5.330651177643153, -1.06505742884149 ],
max: [ 0.6167901044859734, -4.6693486435429055, 2.934442924096579 ]
}
},
{
name: 'ArrowMeshX2',
vertexCount: 78,
normalCount: 78,
uvCount: 0,
triangleCount: 38,
boundingBox : {
min: [ -5.330651171390089, -1.0326269494863676, -0.6059335185163844 ],
max: [ -4.669348828609911, 2.9885841671721116, 0.8202131194767724 ]
}
},
{
name: 'TargetMeshX2',
vertexCount: 54,
normalCount: 54,
uvCount: 0,
triangleCount: 26,
boundingBox : {
min: [ -5.33065128326416, 2.991360902786255, -0.012430161237716675 ],
max: [ -4.66934871673584, 4.039160251617432, 0.6999828815460205 ]
}
},
{
name: 'TargetMeshZ1',
vertexCount: 52,
normalCount: 52,
uvCount: 0,
triangleCount: 26,
boundingBox : {
min: [ -1.3648574352264404, 2.9005930423736572, 4.66934871673584 ],
max: [ -0.6740907430648804, 3.9529545307159424, 5.33065128326416 ]
}
},
{
name: 'ArrowMeshZ1',
vertexCount: 74,
normalCount: 74,
uvCount: 0,
triangleCount: 38,
boundingBox : {
min: [ -1.009571011381568, -1.074115497823536, 4.669348895549774 ],
max: [ 0.6625885973069405, 2.8977772707193465, 5.330651104450226 ]
}
},
{
name: 'TargetMeshX1',
vertexCount: 54,
normalCount: 54,
uvCount: 0,
triangleCount: 26,
boundingBox : {
min: [ 4.66934871673584, 2.4595587253570557, -2.553251266479492 ],
max: [ 5.33065128326416, 3.432579517364502, -1.7226401567459106 ]
}
},
{
name: 'ArrowMeshX1',
vertexCount: 78,
normalCount: 78,
uvCount: 0,
triangleCount: 38,
boundingBox : {
min: [ 4.669348835945129, -1.0589144181932033, -1.7207290818192755 ],
max: [ 5.330651164054871, 2.4574561383341145, 0.9159925616542917 ]
}
},
{
name: 'TargetMeshY1',
vertexCount: 52,
normalCount: 52,
uvCount: 0,
triangleCount: 26,
boundingBox : {
min: [ 2.8218495845794678, 4.669349193572998, -1.6833229064941406 ],
max: [ 3.864471435546875, 5.33065128326416, -1.0113166570663452 ]
}
},
{
name: 'ArrowMeshY1',
vertexCount: 78,
normalCount: 78,
uvCount: 0,
triangleCount: 38,
boundingBox : {
min: [ -1.0826615032554154, 4.669348806142807, -1.093071740019906 ],
max: [ 2.8190779754834807, 5.3306513130664825, 0.7348238365226794 ]
}
},
{
name: 'BaseCubeMesh',
vertexCount: 272,
normalCount: 272,
uvCount: 0,
triangleCount: 140,
boundingBox : {
min: [ -5.000001907348633, -5, -5.000001907348633 ],
max: [ 5.000002384185791, 5, 5.000002861022949 ]
}
}
]
});
]
});
processed += 1;
if (processed == testFileList.length) {
done ();
}
});
}
});
it ('MeshPrimitives_4Vertex', function () {
it ('MeshPrimitives_4Vertex', function (done) {
let testFileList = [
['Mesh_PrimitiveMode', 'Mesh_PrimitiveMode_04.gltf'],
['Mesh_PrimitiveMode', 'Mesh_PrimitiveMode_05.gltf'],
@ -355,90 +391,108 @@ describe ('Gltf Importer', function () {
['Mesh_PrimitiveMode', 'Mesh_PrimitiveMode_12.gltf'],
['Mesh_PrimitiveMode', 'Mesh_PrimitiveMode_13.gltf']
];
let processed = 0;
for (let i = 0; i < testFileList.length; i++) {
let testFile = testFileList[i];
let model = testFiles.ImportGltfFile (testFile[0], testFile[1]);
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 4,
normalCount : 2,
uvCount : 0,
triangleCount : 2,
boundingBox : {
min : [-0.5, -0.5, 0.0],
max : [0.5, 0.5, 0.0]
testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 4,
normalCount : 2,
uvCount : 0,
triangleCount : 2,
boundingBox : {
min : [-0.5, -0.5, 0.0],
max : [0.5, 0.5, 0.0]
}
}
}
]
});
]
});
processed += 1;
if (processed == testFileList.length) {
done ();
}
});
}
});
it ('MeshPrimitives_6Vertex', function () {
it ('MeshPrimitives_6Vertex', function (done) {
let testFileList = [
['Mesh_PrimitiveMode', 'Mesh_PrimitiveMode_06.gltf']
];
let processed = 0;
for (let i = 0; i < testFileList.length; i++) {
let testFile = testFileList[i];
let model = testFiles.ImportGltfFile (testFile[0], testFile[1]);
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 6,
normalCount : 2,
uvCount : 0,
triangleCount : 2,
boundingBox : {
min : [-0.5, -0.5, 0.0],
max : [0.5, 0.5, 0.0]
testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 6,
normalCount : 2,
uvCount : 0,
triangleCount : 2,
boundingBox : {
min : [-0.5, -0.5, 0.0],
max : [0.5, 0.5, 0.0]
}
}
}
]
});
]
});
processed += 1;
if (processed == testFileList.length) {
done ();
}
});
}
});
it ('SimpleSparseAccessor', function () {
it ('SimpleSparseAccessor', function (done) {
let testFileList = [
['SimpleSparseAccessor/glTF', 'SimpleSparseAccessor.gltf'],
['SimpleSparseAccessor/glTF-Embedded', 'SimpleSparseAccessor.gltf']
];
let processed = 0;
for (let i = 0; i < testFileList.length; i++) {
let testFile = testFileList[i];
let model = testFiles.ImportGltfFile (testFile[0], testFile[1]);
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 14,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0.0, 0.0, 0.0],
max : [6.0, 4.0, 0.0]
testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 14,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0.0, 0.0, 0.0],
max : [6.0, 4.0, 0.0]
}
}
}
]
});
]
});
processed += 1;
if (processed == testFileList.length) {
done ();
}
});
}
});
});

File diff suppressed because it is too large Load Diff

View File

@ -2,136 +2,147 @@ var assert = require ('assert');
var testFiles = require ('../utils/testfiles.js');
var testUtils = require ('../utils/testutils.js');
describe ('Off Importer', function() {
it ('single_triangle.off', function () {
var model = testFiles.ImportOffFile ('single_triangle.off');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
describe ('Off Importer', function () {
it ('single_triangle.off', function (done) {
testFiles.ImportOffFile ('single_triangle.off', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
});
done ();
});
});
it ('two_triangles.off', function () {
var model = testFiles.ImportOffFile ('two_triangles.off');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
},
{
vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
it ('two_triangles.off', function (done) {
testFiles.ImportOffFile ('two_triangles.off', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
},
{
vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
});
done ();
});
});
it ('single_rectangle.off', function () {
var model = testFiles.ImportOffFile ('single_rectangle.off');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
},
{
vertices : [0, 0, 0, 1, 1, 0, 0, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
it ('single_rectangle.off', function (done) {
testFiles.ImportOffFile ('single_rectangle.off', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
},
{
vertices : [0, 0, 0, 1, 1, 0, 0, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
});
done ();
});
});
it ('single_triangle_with_comments.off', function () {
var model = testFiles.ImportOffFile ('single_triangle_with_comments.off');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
it ('single_triangle_with_comments.off', function (done) {
testFiles.ImportOffFile ('single_triangle_with_comments.off', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
});
done ();
});
});
it ('cube.off', function () {
var model = testFiles.ImportOffFile ('cube.off');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 8,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
it ('cube.off', function (done) {
testFiles.ImportOffFile ('cube.off', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 8,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
}
}
}
]
]
});
done ();
});
});
});

View File

@ -3,210 +3,226 @@ var testFiles = require ('../utils/testfiles.js');
var testUtils = require ('../utils/testutils.js');
describe ('Ply Importer', function() {
it ('single_triangle.ply', function () {
var model = testFiles.ImportPlyFile ('single_triangle.ply');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
it ('single_triangle.ply', function (done) {
var model = testFiles.ImportPlyFile ('single_triangle.ply', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
});
done ();
});
});
it ('two_triangles.ply', function () {
var model = testFiles.ImportPlyFile ('two_triangles.ply');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
},
{
vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
it ('two_triangles.ply', function (done) {
var model = testFiles.ImportPlyFile ('two_triangles.ply', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
},
{
vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
});
done ();
});
});
it ('single_rectangle.ply', function () {
var model = testFiles.ImportPlyFile ('single_rectangle.ply');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
},
{
vertices : [0, 0, 0, 1, 1, 0, 0, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
it ('single_rectangle.ply', function (done) {
var model = testFiles.ImportPlyFile ('single_rectangle.ply', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
},
{
vertices : [0, 0, 0, 1, 1, 0, 0, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
});
done ();
});
});
it ('single_triangle_with_comments.ply', function () {
var model = testFiles.ImportPlyFile ('single_triangle_with_comments.ply');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
it ('single_triangle_with_comments.ply', function (done) {
var model = testFiles.ImportPlyFile ('single_triangle_with_comments.ply', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
});
done ();
});
});
it ('cube.ply', function (done) {
var model = testFiles.ImportPlyFile ('cube.ply', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 8,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
}
]
}
]
}
]
});
done ();
});
});
it ('cube.ply', function () {
var model = testFiles.ImportPlyFile ('cube.ply');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 8,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
it ('cube_meshlab_ascii.ply', function (done) {
var model = testFiles.ImportPlyFile ('cube_meshlab_ascii.ply', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 8,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
}
}
}
]
});
});
it ('cube_meshlab_ascii.ply', function () {
var model = testFiles.ImportPlyFile ('cube_meshlab_ascii.ply');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 8,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
}
}
]
]
});
done ();
});
});
it ('cube_meshlab_binary.ply', function () {
var model = testFiles.ImportPlyFile ('cube_meshlab_binary.ply');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 8,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
it ('cube_meshlab_binary.ply', function (done) {
var model = testFiles.ImportPlyFile ('cube_meshlab_binary.ply', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 8,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
}
}
}
]
]
});
done ();
});
});
it ('cube_rgb_binary.ply', function () {
var model = testFiles.ImportPlyFile ('cube_rgb_binary.ply');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '#cc0000ff' },
{ name : '#00cc00ff' },
{ name : '#0000ccff' },
{ name : '#cccccc7f' }
],
meshes : [
{
name : '',
vertexCount : 8,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
it ('cube_rgb_binary.ply', function (done) {
var model = testFiles.ImportPlyFile ('cube_rgb_binary.ply', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'Color cc0000ff' },
{ name : 'Color 00cc00ff' },
{ name : 'Color 0000ccff' },
{ name : 'Color cccccc7f' }
],
meshes : [
{
name : '',
vertexCount : 8,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
}
}
}
]
]
});
done ();
});
});
});

View File

@ -3,202 +3,218 @@ var testFiles = require ('../utils/testfiles.js');
var testUtils = require ('../utils/testutils.js');
describe ('Stl Importer', function() {
it ('single_triangle.stl', function () {
var model = testFiles.ImportStlFile ('single_triangle.stl');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : 'MeshName',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
it ('single_triangle.stl', function (done) {
testFiles.ImportStlFile ('single_triangle.stl', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : 'MeshName',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
});
done ();
});
});
it ('single_triangle_with_comments.stl', function () {
var model = testFiles.ImportStlFile ('single_triangle_with_comments.stl');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : 'MeshName',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
it ('single_triangle_with_comments.stl', function (done) {
testFiles.ImportStlFile ('single_triangle_with_comments.stl', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : 'MeshName',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
});
done ();
});
});
it ('single_triangle_no_normal.stl', function () {
var model = testFiles.ImportStlFile ('single_triangle_no_normal.stl');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : 'MeshName',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
it ('single_triangle_no_normal.stl', function (done) {
testFiles.ImportStlFile ('single_triangle_no_normal.stl', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : 'MeshName',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
});
done ();
});
});
it ('two_triangles.stl', function () {
var model = testFiles.ImportStlFile ('two_triangles.stl');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : 'MeshName',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
},
{
vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
it ('two_triangles.stl', function (done) {
testFiles.ImportStlFile ('two_triangles.stl', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObject (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : 'MeshName',
triangles : [
{
vertices : [0, 0, 0, 1, 0, 0, 1, 1, 0],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
},
{
vertices : [0, 0, 1, 1, 0, 1, 1, 1, 1],
normals : [0, 0, 1, 0, 0, 1, 0, 0, 1],
uvs : [],
mat : 0
}
]
}
]
});
done ();
});
});
it ('stl_ascii.stl', function () {
var model = testFiles.ImportStlFile ('stl_ascii.stl');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : 'Untitled-5427e5af',
vertexCount : 1716,
normalCount : 572,
uvCount : 0,
triangleCount : 572,
boundingBox : {
min : [0, -1.10792799192095, 0],
max : [4.94407346265022, 3.31831671830375, 1.2]
it ('stl_ascii.stl', function (done) {
testFiles.ImportStlFile ('stl_ascii.stl', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : 'Untitled-5427e5af',
vertexCount : 1716,
normalCount : 572,
uvCount : 0,
triangleCount : 572,
boundingBox : {
min : [0, -1.10792799192095, 0],
max : [4.94407346265022, 3.31831671830375, 1.2]
}
}
}
]
]
});
done ();
});
});
it ('stl_binary.stl', function () {
var model = testFiles.ImportStlFile ('stl_binary.stl');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 2184,
normalCount : 728,
uvCount : 0,
triangleCount : 728,
boundingBox : {
min : [0, -1.1079280376434326, 0],
max : [5.70156717300415, 3.318316698074341, 1.2000000476837158]
it ('stl_binary.stl', function (done) {
testFiles.ImportStlFile ('stl_binary.stl', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 2184,
normalCount : 728,
uvCount : 0,
triangleCount : 728,
boundingBox : {
min : [0, -1.1079280376434326, 0],
max : [5.70156717300415, 3.318316698074341, 1.2000000476837158]
}
}
}
]
]
});
done ();
});
});
it ('cube_meshlab_ascii.stl', function () {
var model = testFiles.ImportStlFile ('cube_meshlab_ascii.stl');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : 'STL generated by MeshLab',
vertexCount : 36,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
it ('cube_meshlab_ascii.stl', function (done) {
testFiles.ImportStlFile ('cube_meshlab_ascii.stl', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : 'STL generated by MeshLab',
vertexCount : 36,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
}
}
}
]
]
});
done ();
});
});
it ('cube_meshlab_binary.stl', function () {
var model = testFiles.ImportStlFile ('cube_meshlab_binary.stl');
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 36,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
it ('cube_meshlab_binary.stl', function (done) {
testFiles.ImportStlFile ('cube_meshlab_binary.stl', function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : '' }
],
meshes : [
{
name : '',
vertexCount : 36,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
}
}
}
]
]
});
done ();
});
});
});

View File

@ -78,4 +78,62 @@ describe ('Model Utils', function () {
]
});
});
it ('Mesh Volume Calculation', function () {
function GetTriangleArea (v0, v1, v2)
{
let a = OV.CoordDistance3D (v0, v1);
let b = OV.CoordDistance3D (v1, v2);
let c = OV.CoordDistance3D (v0, v2);
let s = (a + b + c) / 2.0;
let areaSquare = s * (s - a) * (s - b) * (s - c);
if (areaSquare < 0.0) {
return 0.0;
}
return Math.sqrt (areaSquare);
}
var model = new OV.Model ();
var cube = new OV.Mesh ();
cube.AddVertex (new OV.Coord3D (0.0, 0.0, 0.0));
cube.AddVertex (new OV.Coord3D (1.0, 0.0, 0.0));
cube.AddVertex (new OV.Coord3D (1.0, 1.0, 0.0));
cube.AddVertex (new OV.Coord3D (0.0, 1.0, 0.0));
cube.AddVertex (new OV.Coord3D (0.0, 0.0, 1.0));
cube.AddVertex (new OV.Coord3D (1.0, 0.0, 1.0));
cube.AddVertex (new OV.Coord3D (1.0, 1.0, 1.0));
cube.AddVertex (new OV.Coord3D (0.0, 1.0, 1.0));
cube.AddTriangle (new OV.Triangle (0, 1, 5));
cube.AddTriangle (new OV.Triangle (0, 5, 4));
cube.AddTriangle (new OV.Triangle (1, 2, 6));
cube.AddTriangle (new OV.Triangle (1, 6, 5));
cube.AddTriangle (new OV.Triangle (2, 3, 7));
cube.AddTriangle (new OV.Triangle (2, 7, 6));
cube.AddTriangle (new OV.Triangle (3, 0, 4));
cube.AddTriangle (new OV.Triangle (3, 4, 7));
cube.AddTriangle (new OV.Triangle (0, 3, 2));
cube.AddTriangle (new OV.Triangle (0, 2, 1));
cube.AddTriangle (new OV.Triangle (4, 5, 6));
cube.AddTriangle (new OV.Triangle (4, 6, 7));
model.AddMesh (cube);
OV.FinalizeModel (model, function () {
return new OV.Material ();
});
let surface = 0.0;
let volume = 0.0;
for (let i = 0; i < model.MeshCount (); i++) {
let mesh = model.GetMesh (i);
for (j = 0; j < mesh.TriangleCount (); j++) {
let triangle = mesh.GetTriangle (j);
let v0 = mesh.GetVertex (triangle.v0);
let v1 = mesh.GetVertex (triangle.v1);
let v2 = mesh.GetVertex (triangle.v2);
surface += GetTriangleArea (v0, v1, v2);
let signedVolume = OV.DotVector3D (v0, OV.CrossVector3D (v1, v2)) / 6.0;
volume += signedVolume;
}
}
assert (OV.IsEqual (volume, 1.0));
assert (OV.IsEqual (surface, 6.0));
});
});

View File

@ -2,37 +2,37 @@ var testUtils = require ('./testutils.js');
module.exports =
{
ImportObjFile : function (fileName)
ImportObjFile : function (fileName, onReady)
{
var importer = new OV.ImporterObj ();
return this.ImportFile (importer, OV.FileFormat.Text, 'obj', fileName);
this.ImportFile (importer, OV.FileFormat.Text, 'obj', fileName, onReady);
},
ImportStlFile : function (fileName)
ImportStlFile : function (fileName, onReady)
{
var importer = new OV.ImporterStl ();
return this.ImportFile (importer, OV.FileFormat.Binary, 'stl', fileName);
this.ImportFile (importer, OV.FileFormat.Binary, 'stl', fileName, onReady);
},
ImportOffFile : function (fileName)
ImportOffFile : function (fileName, onReady)
{
var importer = new OV.ImporterOff ();
return this.ImportFile (importer, OV.FileFormat.Text, 'off', fileName);
this.ImportFile (importer, OV.FileFormat.Text, 'off', fileName, onReady);
},
ImportPlyFile : function (fileName)
ImportPlyFile : function (fileName, onReady)
{
var importer = new OV.ImporterPly ();
return this.ImportFile (importer, OV.FileFormat.Binary, 'ply', fileName);
this.ImportFile (importer, OV.FileFormat.Binary, 'ply', fileName, onReady);
},
Import3dsFile : function (fileName)
Import3dsFile : function (fileName, onReady)
{
var importer = new OV.Importer3ds ();
return this.ImportFile (importer, OV.FileFormat.Binary, '3ds', fileName);
this.ImportFile (importer, OV.FileFormat.Binary, '3ds', fileName, onReady);
},
ImportGltfFile : function (folderName, fileName)
ImportGltfFile : function (folderName, fileName, onReady)
{
let extension = OV.GetFileExtension (fileName);
let format = OV.FileFormat.Text;
@ -40,10 +40,10 @@ module.exports =
format = OV.FileFormat.Binary;
}
var importer = new OV.ImporterGltf ();
return this.ImportFile (importer, format, 'gltf/' + folderName, fileName);
this.ImportFile (importer, format, 'gltf/' + folderName, fileName, onReady);
},
ImportFile : function (importer, format, folder, fileName)
ImportFile : function (importer, format, folder, fileName, onReady)
{
var content = null;
if (format == OV.FileFormat.Text) {
@ -77,9 +77,17 @@ module.exports =
},
getTextureBuffer : function (filePath) {
return buffers.GetTextureBuffer (filePath);
},
onSuccess : function () {
let model = importer.GetModel ();
onReady (model);
},
onError : function () {
onReady (model);
},
onComplete : function () {
}
});
let model = importer.GetModel ();
return model;
}
}

View File

@ -1,7 +1,8 @@
{
"lib_files" : [
"libs/jquery-3.5.1.min.js",
"libs/three.min-126.js"
"libs/three.min-126.js",
"libs/rhino3dm.min.js"
],
"importer_files" : [
"source/core/core.js",
@ -40,6 +41,8 @@
"source/export/exporteroff.js",
"source/export/exportergltf.js",
"source/export/exporter.js",
"source/external/rhino.importer.js",
"source/external/rhino.exporter.js",
"source/external/three.converter.js",
"source/external/three.model.loader.js",
"source/parameters/parameterlist.js",

View File

@ -19,20 +19,19 @@ def GetVersion (rootDir):
return packageJson['version']
def JSHintFolder (folder):
result = Tools.RunCommand (['jshint', folder])
result = Tools.RunCommand ('jshint', [folder])
if result != 0:
return False
return True
def CompressFiles (inputFiles, outputFile):
parameters = []
parameters.append ('google-closure-compiler')
for inputFile in inputFiles:
extension = os.path.splitext (inputFile)[1]
if extension == '.js':
parameters.append ('--js=' + os.path.join ('..', inputFile))
parameters.append ('--js_output_file=' + outputFile)
result = Tools.RunCommand (parameters)
result = Tools.RunCommand ('google-closure-compiler', parameters)
if result != 0:
return False
return True

View File

@ -13,13 +13,9 @@ def WriteContentToFile (filePath, content):
fileObject.write (content)
fileObject.close ()
def RunCommand (commands):
process = subprocess.Popen (commands, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)
out, err = process.communicate ()
if process.returncode != 0:
print (out.decode ())
print (err.decode ())
return process.returncode
def RunCommand (executable, arguments):
command = executable + ' "' + '" "'.join (arguments) + '"'
return os.system (command)
class TokenReplacer:
def __init__ (self, filePath, keepToken):

View File

@ -7,8 +7,7 @@ def Main (argv):
currentDir = os.path.dirname (os.path.abspath (__file__))
os.chdir (currentDir)
imagesPath = os.path.abspath (os.path.join ('..', 'website', 'assets', 'images'))
for i in range (0, 5):
Tools.RunCommand (['svgo', '-r', imagesPath])
Tools.RunCommand ('svgo', ['-r', imagesPath])
return 0
sys.exit (Main (sys.argv))

View File

@ -45,6 +45,8 @@
<script type="text/javascript" src="../../source/export/exporteroff.js"></script>
<script type="text/javascript" src="../../source/export/exportergltf.js"></script>
<script type="text/javascript" src="../../source/export/exporter.js"></script>
<script type="text/javascript" src="../../source/external/rhino.importer.js"></script>
<script type="text/javascript" src="../../source/external/rhino.exporter.js"></script>
<script type="text/javascript" src="../../source/external/three.converter.js"></script>
<script type="text/javascript" src="../../source/external/three.model.loader.js"></script>
<script type="text/javascript" src="../../source/parameters/parameterlist.js"></script>

View File

@ -47,6 +47,8 @@
<script type="text/javascript" src="../../source/export/exporteroff.js"></script>
<script type="text/javascript" src="../../source/export/exportergltf.js"></script>
<script type="text/javascript" src="../../source/export/exporter.js"></script>
<script type="text/javascript" src="../../source/external/rhino.importer.js"></script>
<script type="text/javascript" src="../../source/external/rhino.exporter.js"></script>
<script type="text/javascript" src="../../source/external/three.converter.js"></script>
<script type="text/javascript" src="../../source/external/three.model.loader.js"></script>
<script type="text/javascript" src="../../source/parameters/parameterlist.js"></script>

View File

@ -45,6 +45,8 @@
<script type="text/javascript" src="../../source/export/exporteroff.js"></script>
<script type="text/javascript" src="../../source/export/exportergltf.js"></script>
<script type="text/javascript" src="../../source/export/exporter.js"></script>
<script type="text/javascript" src="../../source/external/rhino.importer.js"></script>
<script type="text/javascript" src="../../source/external/rhino.exporter.js"></script>
<script type="text/javascript" src="../../source/external/three.converter.js"></script>
<script type="text/javascript" src="../../source/external/three.model.loader.js"></script>
<script type="text/javascript" src="../../source/parameters/parameterlist.js"></script>

View File

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 304 B

View File

@ -14,6 +14,7 @@
<!-- libs start -->
<script type="text/javascript" src="../libs/jquery-3.5.1.min.js"></script>
<script type="text/javascript" src="../libs/three.min-126.js"></script>
<script type="text/javascript" src="../libs/rhino3dm.min.js"></script>
<!-- libs end -->
<!-- importer start -->
@ -53,6 +54,8 @@
<script type="text/javascript" src="../source/export/exporteroff.js"></script>
<script type="text/javascript" src="../source/export/exportergltf.js"></script>
<script type="text/javascript" src="../source/export/exporter.js"></script>
<script type="text/javascript" src="../source/external/rhino.importer.js"></script>
<script type="text/javascript" src="../source/external/rhino.exporter.js"></script>
<script type="text/javascript" src="../source/external/three.converter.js"></script>
<script type="text/javascript" src="../source/external/three.model.loader.js"></script>
<script type="text/javascript" src="../source/parameters/parameterlist.js"></script>

View File

@ -11,6 +11,7 @@
<!-- libs start -->
<script type="text/javascript" src="../libs/jquery-3.5.1.min.js"></script>
<script type="text/javascript" src="../libs/three.min-126.js"></script>
<script type="text/javascript" src="../libs/rhino3dm.min.js"></script>
<!-- libs end -->
<!-- meta start -->
@ -53,6 +54,8 @@
<script type="text/javascript" src="../source/export/exporteroff.js"></script>
<script type="text/javascript" src="../source/export/exportergltf.js"></script>
<script type="text/javascript" src="../source/export/exporter.js"></script>
<script type="text/javascript" src="../source/external/rhino.importer.js"></script>
<script type="text/javascript" src="../source/external/rhino.exporter.js"></script>
<script type="text/javascript" src="../source/external/three.converter.js"></script>
<script type="text/javascript" src="../source/external/three.model.loader.js"></script>
<script type="text/javascript" src="../source/parameters/parameterlist.js"></script>
@ -125,12 +128,12 @@
<div class="intro_section only_full_width only_full_height"><img src="assets/images/3dviewer_net_logo.svg" class="intro_logo"></img></div>
<div class="intro_section intro_big_text">
Drag and drop your 3D models here.<br>
Supported formats: <b>obj, 3ds, stl, ply, gltf, glb, off</b>.
<b>obj, 3ds, stl, ply, gltf, glb, 3dm, off</b>
</div>
<div class="intro_section">
Or you can use the browse button above.
</div>
<div class="intro_section only_full_height">
<div class="intro_section">
<div>Example models:</div>
<div class="example_models">
<a href="index.html#model=assets/models/logo.obj,assets/models/logo.mtl">logo</a>

View File

@ -24,7 +24,7 @@
<p>
This is the user manual for the <a href="https://3dviewer.net">3dviewer.net</a> website.
The website can open several 3D file formats and visualize the model in your browser.
Supported file formats: obj, 3ds, stl, ply, gltf, glb, and off.
Supported file formats: obj, 3ds, stl, ply, gltf, glb, 3dm, and off.
</p>
<p>
<ol>
@ -112,6 +112,13 @@
<td class="center green">&#x2713</td>
<td>version 2.0</td>
</tr>
<tr>
<td>3dm</td>
<td>binary</td>
<td class="center green">&#x2713</td>
<td class="center green">&#x2713</td>
<td>experimental</td>
</tr>
<tr>
<td rowspan="2">off</td>
<td>text</td>
@ -173,7 +180,7 @@
<h2 id="embedding_viewer">Embedding the viewer</h2>
<p>
The website allows you to embed a 3D model in your page. It works only if your models are <a href="#loading_models_server">hosted on a web server</a>.
To get the embedding code, click on the embedding button (<img class="inline" src="../assets/images/toolbar/embed.svg"/>) in the toolbar.
To get the embedding code, click on the share model button (<img class="inline" src="../assets/images/toolbar/share.svg"/>) in the toolbar.
</p>
<h3 id="embed_github">Embedding models hosted on GitHub</h3>
@ -191,7 +198,7 @@
https://github.com/kovacsv/Online3DViewer/blob/master/test/testfiles/3ds/texture.png
</div>
</li>
<li>Click on OK, and if the model is loaded, click on the embed button in the toolbar (<img class="inline" src="../assets/images/toolbar/embed.svg"/>).</li>
<li>Click on OK, and if the model is loaded, click on the share button in the toolbar (<img class="inline" src="../assets/images/toolbar/share.svg"/>).</li>
</ol>
</p>
@ -210,7 +217,7 @@
https://www.dropbox.com/s/6dfk1jveevbofxm/texture.png?dl=0
</div>
</li>
<li>Click on OK, and if the model is loaded, click on the embed button in the toolbar (<img class="inline" src="../assets/images/toolbar/embed.svg"/>).</li>
<li>Click on OK, and if the model is loaded, click on the share button in the toolbar (<img class="inline" src="../assets/images/toolbar/share.svg"/>).</li>
</ol>
</p>

View File

@ -74,21 +74,31 @@ OV.ShowOpenUrlDialog = function (onOk)
$('<div>').html (text).addClass ('ov_dialog_section').appendTo (contentDiv);
urlsTextArea.appendTo (contentDiv);
dialog.Show ();
urlsTextArea.focus ();
return dialog;
};
OV.ShowEmbeddingDialog = function (importer, importSettings, camera)
OV.ShowSharingDialog = function (importer, importSettings, camera)
{
function AddCheckboxLine (parentDiv, text, onChange)
function AddCheckboxLine (parentDiv, text, id, onChange)
{
let line = $('<div>').addClass ('ov_dialog_table_row').appendTo (parentDiv);
let check = $('<input>').attr ('type', 'checkbox').attr ('checked', 'true').appendTo (line);
$('<span>').html (text).appendTo (line);
let check = $('<input>').attr ('type', 'checkbox').attr ('checked', 'true').addClass ('ov_dialog_checkradio').attr ('id', id).appendTo (line);
$('<label>').attr ('for', id).html (text).appendTo (line);
check.change (function () {
onChange (check.prop ('checked'));
});
}
function GetSharingLink (params)
{
let builder = OV.CreateUrlBuilder ();
builder.AddModelUrls (params.files);
builder.AddColor (params.color);
let hashParameters = builder.GetParameterList ();
return 'https://3dviewer.net#' + hashParameters;
}
function GetEmbeddingCode (params)
{
let builder = OV.CreateUrlBuilder ();
@ -106,6 +116,70 @@ OV.ShowEmbeddingDialog = function (importer, importSettings, camera)
return embeddingCode;
}
function AddCopyableTextInput (parentDiv, getText)
{
let copyText = 'copy';
let copiedText = 'copied';
let container = $('<div>').addClass ('ov_dialog_copyable_input').appendTo (parentDiv);
let input = $('<input>').prop ('readonly', true).appendTo (container);
let button = $('<div>').addClass ('button').html (copyText).appendTo (container);
button.click (function () {
OV.CopyToClipboard (getText ());
button.fadeOut (200, function () {
button.html (copiedText).fadeIn (200);
setTimeout (function () {
button.fadeOut (200, function () {
button.html (copyText).fadeIn (200);
});
}, 2000);
});
});
return input;
}
function AddSharingLinkTab (parentDiv, sharingLinkParams)
{
let section = $('<div>').addClass ('ov_dialog_section').appendTo (parentDiv);
$('<div>').html ('Sharing Link').addClass ('ov_dialog_inner_title').appendTo (section);
let optionsSection = null;
if (OV.FeatureSet.SetDefaultColor) {
optionsSection = $('<div>').addClass ('ov_dialog_section').appendTo (section);
}
let sharingLinkInput = AddCopyableTextInput (section, function () {
return GetSharingLink (sharingLinkParams);
});
if (OV.FeatureSet.SetDefaultColor) {
AddCheckboxLine (optionsSection, 'Use overridden default color', 'share_color', function (checked) {
sharingLinkParams.color = checked ? importSettings.defaultColor : null;
sharingLinkInput.val (GetSharingLink (sharingLinkParams));
});
sharingLinkParams.color = importSettings.defaultColor;
}
sharingLinkInput.val (GetSharingLink (sharingLinkParams));
}
function AddEmbeddingCodeTab (parentDiv, embeddingCodeParams)
{
let section = $('<div>').addClass ('ov_dialog_section').css ('margin-top', '20px').appendTo (parentDiv);
$('<div>').html ('Embedding Code').addClass ('ov_dialog_inner_title').appendTo (section);
let optionsSection = $('<div>').addClass ('ov_dialog_section').appendTo (section);
let embeddingCodeInput = AddCopyableTextInput (section, function () {
return GetEmbeddingCode (embeddingCodeParams);
});
AddCheckboxLine (optionsSection, 'Use current camera position', 'embed_camera', function (checked) {
embeddingCodeParams.camera = checked ? camera : null;
embeddingCodeInput.val (GetEmbeddingCode (embeddingCodeParams));
});
if (OV.FeatureSet.SetDefaultColor) {
AddCheckboxLine (optionsSection, 'Use overridden default color', 'embed_color', function (checked) {
embeddingCodeParams.color = checked ? importSettings.defaultColor : null;
embeddingCodeInput.val (GetEmbeddingCode (embeddingCodeParams));
});
embeddingCodeParams.color = importSettings.defaultColor;
}
embeddingCodeInput.val (GetEmbeddingCode (embeddingCodeParams));
}
if (!importer.IsOnlyFileSource (OV.FileSource.Url)) {
return OV.ShowMessageDialog (
'Embedding Failed',
@ -121,15 +195,19 @@ OV.ShowEmbeddingDialog = function (importer, importSettings, camera)
modelFiles.push (file.fileUrl);
}
let embeddingParams = {
let sharingLinkParams = {
files : modelFiles,
color : null
};
let embeddingCodeParams = {
files : modelFiles,
camera : camera,
color : null
};
let dialog = new OV.ButtonDialog ();
let urlsTextArea = $('<textarea>').attr ('readonly', 'true').addClass ('ov_dialog_textarea');
let contentDiv = dialog.Init ('Embedding', [
let contentDiv = dialog.Init ('Share', [
{
name : 'Close',
onClick () {
@ -138,41 +216,8 @@ OV.ShowEmbeddingDialog = function (importer, importSettings, camera)
}
]);
let text = 'Embedding options:';
$('<div>').html (text).addClass ('ov_dialog_section').appendTo (contentDiv);
let optionsSection = $('<div>').addClass ('ov_dialog_section').appendTo (contentDiv);
AddCheckboxLine (optionsSection, 'Use current camera position', function (checked) {
embeddingParams.camera = checked ? camera : null;
urlsTextArea.val (GetEmbeddingCode (embeddingParams));
});
if (OV.FeatureSet.SetDefaultColor) {
AddCheckboxLine (optionsSection, 'Use overridden default color', function (checked) {
embeddingParams.color = checked ? importSettings.defaultColor : null;
urlsTextArea.val (GetEmbeddingCode (embeddingParams));
});
embeddingParams.color = importSettings.defaultColor;
}
urlsTextArea.val (GetEmbeddingCode (embeddingParams));
urlsTextArea.appendTo (contentDiv);
let copyToClipboardText = 'copy to clipboard';
let copiedToClipboardText = 'successfully copied';
let innerButtonContainer = $('<div>').addClass ('ov_dialog_inner_buttons').appendTo (contentDiv);
let copyButton = $('<div>').addClass ('ov_dialog_inner_button').html (copyToClipboardText).appendTo (innerButtonContainer);
copyButton.click (function () {
OV.CopyToClipboard (urlsTextArea.val ());
copyButton.fadeOut (200, function () {
copyButton.html (copiedToClipboardText).fadeIn (200);
setTimeout (function () {
copyButton.fadeOut (200, function () {
copyButton.html (copyToClipboardText).fadeIn (200);
});
}, 2000);
});
});
AddSharingLinkTab (contentDiv, sharingLinkParams);
AddEmbeddingCodeTab (contentDiv, embeddingCodeParams);
dialog.Show ();
return dialog;
@ -205,6 +250,7 @@ OV.ShowSettingsDialog = function (importSettings, onOk)
$('<div>').html ('Default Color').addClass ('ov_dialog_table_row_name').appendTo (colorRow);
let valueColumn = $('<div>').addClass ('ov_dialog_table_row_value').appendTo (colorRow);
let colorInput = $('<input>').attr ('type', 'color').addClass ('ov_dialog_color').appendTo (valueColumn);
$('<span>').addClass ('ov_dialog_table_row_comment').html ('(For surfaces with no material)').appendTo (valueColumn);
colorInput.val ('#' + OV.ColorToHexString (dialogSettings.defaultColor));
colorInput.change (function () {
let colorStr = colorInput.val ().substr (1);

View File

@ -1,3 +1,9 @@
OV.ExportType =
{
Model : 1,
Image : 2
};
OV.ExportDialog = class
{
constructor (callbacks)
@ -8,34 +14,47 @@ OV.ExportDialog = class
{
name : 'obj',
formats : [
{ name : 'text', format : OV.FileFormat.Text, extension : 'obj' }
{ name : 'text', type: OV.ExportType.Model, format : OV.FileFormat.Text, extension : 'obj' }
]
},
{
name : 'stl',
formats : [
{ name : 'text', format : OV.FileFormat.Text, extension : 'stl' },
{ name : 'binary', format : OV.FileFormat.Binary, extension : 'stl' }
{ name : 'text', type: OV.ExportType.Model, format : OV.FileFormat.Text, extension : 'stl' },
{ name : 'binary', type: OV.ExportType.Model, format : OV.FileFormat.Binary, extension : 'stl' }
]
},
{
name : 'ply',
formats : [
{ name : 'text', format : OV.FileFormat.Text, extension : 'ply' },
{ name : 'binary', format : OV.FileFormat.Binary, extension : 'ply' }
{ name : 'text', type: OV.ExportType.Model, format : OV.FileFormat.Text, extension : 'ply' },
{ name : 'binary', type: OV.ExportType.Model, format : OV.FileFormat.Binary, extension : 'ply' }
]
},
{
name : 'gltf',
formats : [
{ name : 'text', format : OV.FileFormat.Text, extension : 'gltf' },
{ name : 'binary', format : OV.FileFormat.Binary, extension : 'glb' }
{ name : 'text', type: OV.ExportType.Model, format : OV.FileFormat.Text, extension : 'gltf' },
{ name : 'binary', type: OV.ExportType.Model, format : OV.FileFormat.Binary, extension : 'glb' }
]
},
{
name : 'off',
formats : [
{ name : 'text', format : OV.FileFormat.Text, extension : 'off' }
{ name : 'text', type: OV.ExportType.Model, format : OV.FileFormat.Text, extension : 'off' }
]
},
{
name : '3dm',
formats : [
{ name : 'binary', type: OV.ExportType.Model, format : OV.FileFormat.Binary, extension : '3dm' }
]
},
{
name : 'png',
formats : [
{ name : 'current size', type: OV.ExportType.Image, width : null, height : null, extension : 'png' },
{ name : 'fixed size (1920x1080)', type: OV.ExportType.Image, width : 1920, height : 1080, extension : 'png' }
]
}
];
@ -46,7 +65,7 @@ OV.ExportDialog = class
};
}
Show (model)
Show (model, viewer)
{
if (model === null) {
let messageDialog = OV.ShowMessageDialog (
@ -76,7 +95,7 @@ OV.ExportDialog = class
return;
}
mainDialog.Hide ();
obj.ExportFormat (model);
obj.ExportFormat (model, viewer);
}
}
]);
@ -119,7 +138,7 @@ OV.ExportDialog = class
for (let i = 0; i < exportFormat.formats.length; i++) {
let format = exportFormat.formats[i];
let formatDiv = $('<div>').addClass ('ov_dialog_table_row').appendTo (this.formatParameters.formatSettingsDiv);
let formatInput = $('<input>').addClass ('ov_dialog_table_radio').attr ('type', 'radio').attr ('id', format.name).attr ('name', 'format').appendTo (formatDiv);
let formatInput = $('<input>').addClass ('ov_dialog_checkradio').attr ('type', 'radio').attr ('id', format.name).attr ('name', 'format').appendTo (formatDiv);
$('<label>').attr ('for', format.name).html (format.name).appendTo (formatDiv);
if (i === 0) {
formatInput.prop ('checked', true);
@ -131,30 +150,48 @@ OV.ExportDialog = class
}
}
ExportFormat (model)
ExportFormat (model, viewer)
{
let format = this.formatParameters.selectedFormat;
if (format === null) {
let selectedFormat = this.formatParameters.selectedFormat;
if (selectedFormat === null) {
return;
}
let obj = this;
let progressDialog = new OV.ProgressDialog ();
progressDialog.Show ('Exporting Model');
OV.RunTaskAsync (function () {
let exporter = new OV.Exporter ();
let files = exporter.Export (model, format.format, format.extension);
if (files.length === 0) {
progressDialog.Hide ();
} else if (files.length === 1) {
progressDialog.Hide ();
let file = files[0];
OV.DownloadArrayBufferAsFile (file.GetContent (), file.GetName ());
} else if (files.length > 1) {
progressDialog.Hide ();
obj.ShowExportedFiles (files);
if (selectedFormat.type === OV.ExportType.Model) {
let obj = this;
let progressDialog = new OV.ProgressDialog ();
progressDialog.Show ('Exporting Model');
OV.RunTaskAsync (function () {
let exporter = new OV.Exporter ();
exporter.AddExporter (new OV.Exporter3dm ());
exporter.Export (model, selectedFormat.format, selectedFormat.extension, {
onError : function () {
progressDialog.Hide ();
},
onSuccess : function (files) {
if (files.length === 0) {
progressDialog.Hide ();
} else if (files.length === 1) {
progressDialog.Hide ();
let file = files[0];
OV.DownloadArrayBufferAsFile (file.GetContent (), file.GetName ());
} else if (files.length > 1) {
progressDialog.Hide ();
obj.ShowExportedFiles (files);
}
}
});
});
} else if (selectedFormat.type === OV.ExportType.Image) {
let url = null;
if (selectedFormat.width === null || selectedFormat.height === null) {
let size = viewer.GetImageSize ();
url = viewer.GetImageAsDataUrl (size.width, size.height);
} else {
url = viewer.GetImageAsDataUrl (selectedFormat.width, selectedFormat.height);
}
});
OV.DownloadUrlAsFile (url, 'model.' + selectedFormat.extension);
}
}
ShowExportedFiles (files)

View File

@ -5,7 +5,7 @@ OV.InitModelLoader = function (modelLoader, callbacks)
if (importError.code === OV.ImportErrorCode.NoImportableFile) {
return OV.ShowMessageDialog (
'Something went wrong',
'No importable file found. You can open obj, 3ds, stl, ply, gltf, glb and off files.',
'No importable file found. You can open obj, 3ds, stl, ply, gltf, glb, 3dm, and off files.',
importError.message
);
} else if (importError.code === OV.ImportErrorCode.ImportFailed) {

View File

@ -100,16 +100,22 @@ OV.CopyToClipboard = function (text)
document.body.removeChild (input);
};
OV.DownloadArrayBufferAsFile = function (arrayBuffer, fileName)
OV.DownloadUrlAsFile = function (url, fileName)
{
let link = document.createElement ('a');
link.href = OV.CreateObjectUrl (arrayBuffer);
link.href = url;
link.download = fileName;
document.body.appendChild (link);
link.click ();
document.body.removeChild (link);
};
OV.DownloadArrayBufferAsFile = function (arrayBuffer, fileName)
{
let url = OV.CreateObjectUrl (arrayBuffer);
OV.DownloadUrlAsFile (url, fileName);
};
OV.CreateIconButton = function (iconName, hoverIconName, title, link)
{
let buttonLink = $('<a>');

View File

@ -385,6 +385,12 @@ div.ov_dialog div.ov_dialog_title
font-weight: bold;
}
div.ov_dialog div.ov_dialog_inner_title
{
font-weight: bold;
margin-bottom: 10px;
}
div.ov_dialog div.ov_dialog_content
{
padding: 20px 0px;
@ -477,6 +483,7 @@ div.ov_dialog input.ov_dialog_color
{
width: 36px;
height: 18px;
margin-right: 10px;
}
div.ov_dialog div.ov_dialog_file_list
@ -506,6 +513,39 @@ div.ov_dialog div.ov_dialog_file_link_text
float: left;
}
div.ov_dialog div.ov_dialog_copyable_input
{
padding: 3px;
border: 1px solid #dddddd;
border-radius: 5px;
overflow: auto;
}
div.ov_dialog div.ov_dialog_copyable_input input
{
color: #666666;
width: 70%;
margin-top: 6px;
box-sizing: border-box;
outline: none;
float: left;
border: 0px;
box-sizing: border-box;
}
div.ov_dialog div.ov_dialog_copyable_input div.button
{
color: #3393bd;
width: 28%;
text-align: center;
padding: 3px;
border: 1px solid #3393bd;
border-radius: 5px;
box-sizing: border-box;
cursor: pointer;
float: right;
}
div.ov_dialog div.ov_dialog_inner_buttons
{
margin-bottom: 10px;
@ -536,7 +576,13 @@ div.ov_dialog div.ov_dialog_table_row_value
float: left;
}
div.ov_dialog input.ov_dialog_table_radio
div.ov_dialog span.ov_dialog_table_row_comment
{
color: #444444;
font-size: 15px;
}
div.ov_dialog input.ov_dialog_checkradio
{
margin-right: 10px;
}
@ -672,7 +718,6 @@ div.intro div.intro_section
{
font-size: 16px;
line-height: 20px;
margin: 20px 0px;
}
div.intro div.intro_big_text
@ -709,7 +754,7 @@ div.ov_progress
div.intro div.intro_section
{
margin: 20px 0px;
margin: 15px 0px;
}
}

View File

@ -97,7 +97,7 @@ OV.Website = class
OnModelClicked (button, isCtrlPressed, mouseCoordinates)
{
if (button === 1) {
let meshUserData = this.viewer.GetMeshUnderMouse (mouseCoordinates);
let meshUserData = this.viewer.GetMeshUserDataUnderMouse (mouseCoordinates);
if (meshUserData === null) {
this.menu.SetSelection (null);
} else {
@ -285,10 +285,10 @@ OV.Website = class
obj.dialog = dialog;
}
});
exportDialog.Show (obj.model);
exportDialog.Show (obj.model, obj.viewer);
});
AddButton (this.toolbar, 'embed', 'Get embedding code', true, function () {
obj.dialog = OV.ShowEmbeddingDialog (importer, obj.importSettings, obj.viewer.GetCamera ());
AddButton (this.toolbar, 'share', 'Share model', true, function () {
obj.dialog = OV.ShowSharingDialog (importer, obj.importSettings, obj.viewer.GetCamera ());
});
if (OV.FeatureSet.SetDefaultColor) {
AddSeparator (this.toolbar, true);