diff --git a/source/engine/export/exportermodel.js b/source/engine/export/exportermodel.js index 6c02a4e5..11eb69a3 100644 --- a/source/engine/export/exportermodel.js +++ b/source/engine/export/exportermodel.js @@ -1,6 +1,7 @@ import { CopyObjectAttributes } from '../core/core.js'; import { Transformation } from '../geometry/transformation.js'; import { CalculateTriangleNormal, TransformMesh } from '../model/meshutils.js'; +import { ColorComponentFromFloat } from '../model/color.js'; export class ExporterSettings { @@ -147,6 +148,46 @@ export class ExporterModel } } + EnumerateVerticesAndTrianglesColor (callbacks) + { + let transformedMeshes = []; + this.EnumerateTransformedMeshInstances ((mesh) => { + transformedMeshes.push (mesh); + }); + + for (let mesh of transformedMeshes) { + let hasVertexColors = (mesh.VertexCount () === mesh.VertexColorCount ()); + let vertexColor = undefined; + for (let vertexIndex = 0; vertexIndex < mesh.VertexCount (); vertexIndex++) { + if (hasVertexColors) + vertexColor = mesh.GetVertexColor (vertexIndex); + + let vertex = mesh.GetVertex (vertexIndex); + callbacks.onVertexColor (vertex.x, vertex.y, vertex.z, vertexColor); + } + } + + let vertexOffset = 0; + for (let mesh of transformedMeshes) { + let hasVertexColors = (mesh.VertexCount () === mesh.VertexColorCount ()); + for (const triangle of mesh.triangles) { + let material = this.GetMaterial (triangle.mat); + let triangleColor = { + r : Math.round (material.color.r), + g : Math.round (material.color.g), + b : Math.round (material.color.b), + a : ColorComponentFromFloat (material.opacity), + }; + + if (hasVertexColors) + triangleColor = undefined; + + callbacks.onTriangleColor (triangle.v0 + vertexOffset, triangle.v1 + vertexOffset, triangle.v2 + vertexOffset, triangleColor); + } + vertexOffset += mesh.VertexCount (); + } + } + EnumerateTrianglesWithNormals (onTriangle) { this.EnumerateTransformedMeshInstances ((mesh) => { diff --git a/source/engine/export/exporteroff.js b/source/engine/export/exporteroff.js index 44aa058a..893e5225 100644 --- a/source/engine/export/exporteroff.js +++ b/source/engine/export/exporteroff.js @@ -23,12 +23,30 @@ export class ExporterOff extends ExporterBase offWriter.WriteLine ('OFF'); offWriter.WriteArrayLine ([exporterModel.VertexCount (), exporterModel.TriangleCount (), 0]); - exporterModel.EnumerateVerticesAndTriangles ({ - onVertex : function (x, y, z) { - offWriter.WriteArrayLine ([x, y, z]); + exporterModel.EnumerateVerticesAndTrianglesColor ({ + onVertexColor : function (x, y, z, color) { + if (color) + { + offWriter.WriteArrayLine ([x, y, z, color.r, color.g, color.b]); + } + else + { + offWriter.WriteArrayLine ([x, y, z]); + } }, - onTriangle : function (v0, v1, v2) { - offWriter.WriteArrayLine ([3, v0, v1, v2]); + onTriangleColor : function (v0, v1, v2, color) { + if (color) + { + // ignore alpha with max value + if (color.a === 255) + offWriter.WriteArrayLine ([3, v0, v1, v2, color.r, color.g, color.b]); + else + offWriter.WriteArrayLine ([3, v0, v1, v2, color.r, color.g, color.b, color.a]); + } + else + { + offWriter.WriteArrayLine ([3, v0, v1, v2]); + } } }); diff --git a/source/engine/import/importeroff.js b/source/engine/import/importeroff.js index 371ac99b..a0c9fffb 100644 --- a/source/engine/import/importeroff.js +++ b/source/engine/import/importeroff.js @@ -1,7 +1,7 @@ import { Coord3D } from '../geometry/coord3d.js'; import { Direction } from '../geometry/geometry.js'; import { ArrayBufferToUtf8String } from '../io/bufferutils.js'; -import { RGBColor, ColorComponentFromFloat } from '../model/color.js'; +import { RGBColor, RGBAColor, ColorComponentFromFloat } from '../model/color.js'; import { Mesh } from '../model/mesh.js'; import { Triangle } from '../model/triangle.js'; import { ImporterBase } from './importerbase.js'; @@ -114,13 +114,25 @@ export class ImporterOff extends ImporterBase return; } let materialIndex = null; - if (!hasVertexColors && parameters.length >= vertexCount + 4) { - let color = new RGBColor ( - CreateColorComponent (parameters[vertexCount + 1]), - CreateColorComponent (parameters[vertexCount + 2]), - CreateColorComponent (parameters[vertexCount + 3]) - ); - materialIndex = this.colorToMaterial.GetMaterialIndex (color.r, color.g, color.b); + if (!hasVertexColors) + { + if (parameters.length >= vertexCount + 5) { + let color = new RGBAColor ( + CreateColorComponent (parameters[vertexCount + 1]), + CreateColorComponent (parameters[vertexCount + 2]), + CreateColorComponent (parameters[vertexCount + 3]), + CreateColorComponent (parameters[vertexCount + 4]) + ); + materialIndex = this.colorToMaterial.GetMaterialIndex (color.r, color.g, color.b, color.a); + } + else if (parameters.length >= vertexCount + 4) { + let color = new RGBColor ( + CreateColorComponent (parameters[vertexCount + 1]), + CreateColorComponent (parameters[vertexCount + 2]), + CreateColorComponent (parameters[vertexCount + 3]) + ); + materialIndex = this.colorToMaterial.GetMaterialIndex (color.r, color.g, color.b); + } } for (let i = 0; i < vertexCount - 2; i++) { let v0 = parseInt (parameters[1]); diff --git a/test/tests/exporter_test.js b/test/tests/exporter_test.js index 5425add0..75cda203 100644 --- a/test/tests/exporter_test.js +++ b/test/tests/exporter_test.js @@ -257,10 +257,10 @@ describe ('Exporter', function () { '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', + '3 0 1 2 255 0 0', + '3 3 4 5 255 0 0', + '3 3 5 6 0 255 0', + '3 3 7 5 0 255 0', '' ].join ('\n')); diff --git a/test/tests/exportimport_test.js b/test/tests/exportimport_test.js index d20cd057..4aeb0ede 100644 --- a/test/tests/exportimport_test.js +++ b/test/tests/exportimport_test.js @@ -267,7 +267,11 @@ describe ('Export-Import Test', function () { it ('Export-Import Off', function (done) { let model = CreateTestModel (); ExportImport (model, OV.FileFormat.Text, 'off', (model2) => { - CheckSingleMeshModel (model, model2); + // Single Mesh Model with 2 materials + assert.strictEqual (model2.MaterialCount (), 2); + assert.strictEqual (model2.MeshInstanceCount (), 1); + assert.strictEqual (model.TriangleCount (), model2.TriangleCount ()); + CheckModelBounds (model, model2); done (); }); }); diff --git a/website/assets/models/cube.off b/website/assets/models/cube.off index 3132aeb9..4b5c47af 100644 --- a/website/assets/models/cube.off +++ b/website/assets/models/cube.off @@ -1,7 +1,7 @@ OFF # cube.off # A cube - + 8 6 12 1.0 0.0 1.4142 0.0 1.0 1.4142 @@ -14,6 +14,6 @@ OFF 4 0 1 2 3 255 0 0 #red 4 7 4 0 3 0 255 0 #green 4 4 5 1 0 0 0 255 #blue -4 5 6 2 1 0 255 0 -4 3 2 6 7 0 0 255 -4 6 5 4 7 255 0 0 \ No newline at end of file +4 5 6 2 1 0 255 0 100 +4 3 2 6 7 0 0 255 100 +4 6 5 4 7 255 0 0 100 diff --git a/website/assets/models/cube_vertex.off b/website/assets/models/cube_vertex.off new file mode 100644 index 00000000..cabf0b33 --- /dev/null +++ b/website/assets/models/cube_vertex.off @@ -0,0 +1,19 @@ +OFF +# cube_vertex.off +# A cube + +8 6 12 + 1.0 0.0 1.4142 255 0 0 #red + 0.0 1.0 1.4142 255 0 0 #red +-1.0 0.0 1.4142 255 0 0 #red + 0.0 -1.0 1.4142 255 0 0 #red + 1.0 0.0 0.0 0 0 255 #blue + 0.0 1.0 0.0 0 0 255 #blue +-1.0 0.0 0.0 0 0 255 #blue + 0.0 -1.0 0.0 0 0 255 #blue +4 0 1 2 3 +4 7 4 0 3 +4 4 5 1 0 +4 5 6 2 1 +4 3 2 6 7 +4 6 5 4 7