molstar
Version:
A comprehensive macromolecular library.
203 lines • 12.3 kB
JavaScript
"use strict";
/**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Sukolsak Sakshuwong <sukolsak@stanford.edu>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ObjExporter = void 0;
var tslib_1 = require("tslib");
var ascii_1 = require("../../mol-io/common/ascii");
var linear_algebra_1 = require("../../mol-math/linear-algebra");
var mol_util_1 = require("../../mol-util");
var color_1 = require("../../mol-util/color/color");
var zip_1 = require("../../mol-util/zip/zip");
var mesh_exporter_1 = require("./mesh-exporter");
// avoiding namespace lookup improved performance in Chrome (Aug 2020)
var v3fromArray = linear_algebra_1.Vec3.fromArray;
var v3transformMat4 = linear_algebra_1.Vec3.transformMat4;
var v3transformMat3 = linear_algebra_1.Vec3.transformMat3;
var mat3directionTransform = linear_algebra_1.Mat3.directionTransform;
var ObjExporter = /** @class */ (function (_super) {
(0, tslib_1.__extends)(ObjExporter, _super);
function ObjExporter(filename, boundingBox) {
var _this = _super.call(this) || this;
_this.filename = filename;
_this.fileExtension = 'zip';
_this.obj = mol_util_1.StringBuilder.create();
_this.mtl = mol_util_1.StringBuilder.create();
_this.vertexOffset = 0;
_this.materialSet = new Set();
mol_util_1.StringBuilder.writeSafe(_this.obj, "mtllib " + filename + ".mtl\n");
var tmpV = (0, linear_algebra_1.Vec3)();
linear_algebra_1.Vec3.add(tmpV, boundingBox.min, boundingBox.max);
linear_algebra_1.Vec3.scale(tmpV, tmpV, -0.5);
_this.centerTransform = linear_algebra_1.Mat4.fromTranslation((0, linear_algebra_1.Mat4)(), tmpV);
return _this;
}
ObjExporter.prototype.updateMaterial = function (color, alpha) {
if (this.currentColor === color && this.currentAlpha === alpha)
return;
this.currentColor = color;
this.currentAlpha = alpha;
var material = color_1.Color.toHexString(color) + alpha;
mol_util_1.StringBuilder.writeSafe(this.obj, "usemtl " + material);
mol_util_1.StringBuilder.newline(this.obj);
if (!this.materialSet.has(material)) {
this.materialSet.add(material);
var _a = color_1.Color.toRgbNormalized(color), r = _a[0], g = _a[1], b = _a[2];
var mtl = this.mtl;
mol_util_1.StringBuilder.writeSafe(mtl, "newmtl " + material + "\n");
mol_util_1.StringBuilder.writeSafe(mtl, 'illum 2\n'); // illumination model
mol_util_1.StringBuilder.writeSafe(mtl, 'Ns 163\n'); // specular exponent
mol_util_1.StringBuilder.writeSafe(mtl, 'Ni 0.001\n'); // optical density a.k.a. index of refraction
mol_util_1.StringBuilder.writeSafe(mtl, 'Ka 0 0 0\n'); // ambient reflectivity
mol_util_1.StringBuilder.writeSafe(mtl, 'Kd '); // diffuse reflectivity
mol_util_1.StringBuilder.writeFloat(mtl, r, 1000);
mol_util_1.StringBuilder.whitespace1(mtl);
mol_util_1.StringBuilder.writeFloat(mtl, g, 1000);
mol_util_1.StringBuilder.whitespace1(mtl);
mol_util_1.StringBuilder.writeFloat(mtl, b, 1000);
mol_util_1.StringBuilder.newline(mtl);
mol_util_1.StringBuilder.writeSafe(mtl, 'Ks 0.25 0.25 0.25\n'); // specular reflectivity
mol_util_1.StringBuilder.writeSafe(mtl, 'd '); // dissolve
mol_util_1.StringBuilder.writeFloat(mtl, alpha, 1000);
mol_util_1.StringBuilder.newline(mtl);
}
};
ObjExporter.prototype.addMeshWithColors = function (input) {
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
var mesh, values, isGeoTexture, webgl, ctx, obj, t, n, tmpV, stride, groupCount, colorType, uAlpha, dTransparency, tTransparency, aTransform, instanceCount, interpolatedColors, instanceIndex, _a, vertices, normals, indices, groups, vertexCount, drawCount, i, i, i, v, color, alpha, group, transparency, v1, v2, v3;
return (0, tslib_1.__generator)(this, function (_b) {
switch (_b.label) {
case 0:
mesh = input.mesh, values = input.values, isGeoTexture = input.isGeoTexture, webgl = input.webgl, ctx = input.ctx;
obj = this.obj;
t = (0, linear_algebra_1.Mat4)();
n = (0, linear_algebra_1.Mat3)();
tmpV = (0, linear_algebra_1.Vec3)();
stride = isGeoTexture ? 4 : 3;
groupCount = values.uGroupCount.ref.value;
colorType = values.dColorType.ref.value;
uAlpha = values.uAlpha.ref.value;
dTransparency = values.dTransparency.ref.value;
tTransparency = values.tTransparency.ref.value;
aTransform = values.aTransform.ref.value;
instanceCount = values.uInstanceCount.ref.value;
if (colorType === 'volume' || colorType === 'volumeInstance') {
interpolatedColors = ObjExporter.getInterpolatedColors(mesh.vertices, mesh.vertexCount, values, stride, colorType, webgl);
ObjExporter.quantizeColors(interpolatedColors, mesh.vertexCount);
}
return [4 /*yield*/, ctx.update({ isIndeterminate: false, current: 0, max: instanceCount })];
case 1:
_b.sent();
instanceIndex = 0;
_b.label = 2;
case 2:
if (!(instanceIndex < instanceCount)) return [3 /*break*/, 6];
if (!ctx.shouldUpdate) return [3 /*break*/, 4];
return [4 /*yield*/, ctx.update({ current: instanceIndex + 1 })];
case 3:
_b.sent();
_b.label = 4;
case 4:
_a = ObjExporter.getInstance(input, instanceIndex), vertices = _a.vertices, normals = _a.normals, indices = _a.indices, groups = _a.groups, vertexCount = _a.vertexCount, drawCount = _a.drawCount;
linear_algebra_1.Mat4.fromArray(t, aTransform, instanceIndex * 16);
linear_algebra_1.Mat4.mul(t, this.centerTransform, t);
mat3directionTransform(n, t);
// position
for (i = 0; i < vertexCount; ++i) {
v3transformMat4(tmpV, v3fromArray(tmpV, vertices, i * stride), t);
mol_util_1.StringBuilder.writeSafe(obj, 'v ');
mol_util_1.StringBuilder.writeFloat(obj, tmpV[0], 1000);
mol_util_1.StringBuilder.whitespace1(obj);
mol_util_1.StringBuilder.writeFloat(obj, tmpV[1], 1000);
mol_util_1.StringBuilder.whitespace1(obj);
mol_util_1.StringBuilder.writeFloat(obj, tmpV[2], 1000);
mol_util_1.StringBuilder.newline(obj);
}
// normal
for (i = 0; i < vertexCount; ++i) {
v3transformMat3(tmpV, v3fromArray(tmpV, normals, i * stride), n);
mol_util_1.StringBuilder.writeSafe(obj, 'vn ');
mol_util_1.StringBuilder.writeFloat(obj, tmpV[0], 100);
mol_util_1.StringBuilder.whitespace1(obj);
mol_util_1.StringBuilder.writeFloat(obj, tmpV[1], 100);
mol_util_1.StringBuilder.whitespace1(obj);
mol_util_1.StringBuilder.writeFloat(obj, tmpV[2], 100);
mol_util_1.StringBuilder.newline(obj);
}
// face
for (i = 0; i < drawCount; i += 3) {
v = isGeoTexture ? i : indices[i];
color = ObjExporter.getColor(values, groups, vertexCount, instanceIndex, isGeoTexture, interpolatedColors, v);
alpha = uAlpha;
if (dTransparency) {
group = isGeoTexture ? ObjExporter.getGroup(groups, i) : groups[indices[i]];
transparency = tTransparency.array[instanceIndex * groupCount + group] / 255;
alpha *= 1 - transparency;
}
this.updateMaterial(color, alpha);
v1 = this.vertexOffset + (isGeoTexture ? i : indices[i]) + 1;
v2 = this.vertexOffset + (isGeoTexture ? i + 1 : indices[i + 1]) + 1;
v3 = this.vertexOffset + (isGeoTexture ? i + 2 : indices[i + 2]) + 1;
mol_util_1.StringBuilder.writeSafe(obj, 'f ');
mol_util_1.StringBuilder.writeInteger(obj, v1);
mol_util_1.StringBuilder.writeSafe(obj, '//');
mol_util_1.StringBuilder.writeIntegerAndSpace(obj, v1);
mol_util_1.StringBuilder.writeInteger(obj, v2);
mol_util_1.StringBuilder.writeSafe(obj, '//');
mol_util_1.StringBuilder.writeIntegerAndSpace(obj, v2);
mol_util_1.StringBuilder.writeInteger(obj, v3);
mol_util_1.StringBuilder.writeSafe(obj, '//');
mol_util_1.StringBuilder.writeInteger(obj, v3);
mol_util_1.StringBuilder.newline(obj);
}
this.vertexOffset += vertexCount;
_b.label = 5;
case 5:
++instanceIndex;
return [3 /*break*/, 2];
case 6: return [2 /*return*/];
}
});
});
};
ObjExporter.prototype.getData = function () {
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
return (0, tslib_1.__generator)(this, function (_a) {
return [2 /*return*/, {
obj: mol_util_1.StringBuilder.getString(this.obj),
mtl: mol_util_1.StringBuilder.getString(this.mtl)
}];
});
});
};
ObjExporter.prototype.getBlob = function (ctx) {
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
var _a, obj, mtl, objData, mtlData, zipDataObj, _b;
var _c;
return (0, tslib_1.__generator)(this, function (_d) {
switch (_d.label) {
case 0: return [4 /*yield*/, this.getData()];
case 1:
_a = _d.sent(), obj = _a.obj, mtl = _a.mtl;
objData = new Uint8Array(obj.length);
(0, ascii_1.asciiWrite)(objData, obj);
mtlData = new Uint8Array(mtl.length);
(0, ascii_1.asciiWrite)(mtlData, mtl);
zipDataObj = (_c = {},
_c[this.filename + '.obj'] = objData,
_c[this.filename + '.mtl'] = mtlData,
_c);
_b = Blob.bind;
return [4 /*yield*/, (0, zip_1.zip)(ctx, zipDataObj)];
case 2: return [2 /*return*/, new (_b.apply(Blob, [void 0, [_d.sent()], { type: 'application/zip' }]))()];
}
});
});
};
return ObjExporter;
}(mesh_exporter_1.MeshExporter));
exports.ObjExporter = ObjExporter;
//# sourceMappingURL=obj-exporter.js.map