///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2018 Statoil ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. // // See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "VdeFileExporter.h" #include "VdeArrayDataPacket.h" #include "RicHoloLensExportImpl.h" #include "RifJsonEncodeDecode.h" #include "RiaLogging.h" #include "cvfPart.h" #include "cvfScene.h" #include "cvfDrawableGeo.h" #include "cvfPrimitiveSet.h" #include "cvfTransform.h" #include "cvfRenderStateTextureBindings.h" #include "cvfTexture.h" #include "cvfEffect.h" #include "cvfTrace.h" #include #include #include //================================================================================================== // // // //================================================================================================== //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- VdeFileExporter::VdeFileExporter(QString absOutputFolder) : m_absOutputFolder(absOutputFolder) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool VdeFileExporter::exportViewContents(const RimGridView& view) { std::vector exportPartsArr = RicHoloLensExportImpl::partsForExport(view); std::vector meshArr; for (const auto& exportPart : exportPartsArr) { VdeMesh mesh; if (extractMeshFromExportPart(exportPart, &mesh)) { meshArr.push_back(mesh); } } std::vector meshArrayIdsArr; const size_t meshCount = meshArr.size(); cvf::Trace::show("Exporting %d meshes", meshCount); size_t totNumPrimitives = 0; int nextArrayId = 0; for (size_t i = 0; i < meshCount; i++) { const VdeMesh& mesh = meshArr[i]; const size_t primCount = mesh.connArr.size()/mesh.verticesPerPrimitive; totNumPrimitives += primCount; cvf::Trace::show(" %2d: primCount=%d meshSourceObjName='%s'", i, primCount, mesh.meshSourceObjName.toLatin1().constData()); VdeMeshArrayIds meshArrayIds; { meshArrayIds.vertexArrId = nextArrayId++; const float* floatArr = reinterpret_cast(mesh.vertexArr->ptr()); VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromFloat32Arr(meshArrayIds.vertexArrId, floatArr, 3*mesh.vertexArr->size()); writeDataPacketToFile(dataPacket.arrayId(), dataPacket); // Debug testing of decoding //debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr)); } { meshArrayIds.connArrId = nextArrayId++; const unsigned int* uintArr = mesh.connArr.data(); VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromUint32Arr(meshArrayIds.connArrId, uintArr, mesh.connArr.size()); writeDataPacketToFile(dataPacket.arrayId(), dataPacket); // Debug testing of decoding //debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr)); } if (mesh.texCoordArr.notNull() && mesh.texImage.notNull()) { { meshArrayIds.texCoordsArrId = nextArrayId++; const float* floatArr = reinterpret_cast(mesh.texCoordArr->ptr()); VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromFloat32Arr(meshArrayIds.texCoordsArrId, floatArr, 3*mesh.vertexArr->size()); writeDataPacketToFile(dataPacket.arrayId(), dataPacket); // Debug testing of decoding //debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr)); } { meshArrayIds.texImageArrId = nextArrayId++; cvf::ref byteArr = mesh.texImage->toRgb(); VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromUint8ImageRGBArr(meshArrayIds.texImageArrId, mesh.texImage->width(), mesh.texImage->height(), byteArr->ptr(), byteArr->size()); writeDataPacketToFile(dataPacket.arrayId(), dataPacket); // Debug testing of decoding //debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr)); } } meshArrayIdsArr.push_back(meshArrayIds); } QString jsonFileName = m_absOutputFolder + "/modelMeta.json"; if (!writeModelMetaJsonFile(meshArr, meshArrayIdsArr, jsonFileName)) { return false; } cvf::Trace::show("Total number of primitives exported: %d", totNumPrimitives); return true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool VdeFileExporter::extractMeshFromExportPart(const VdeExportPart& exportPart, VdeMesh* mesh) { const cvf::Part* cvfPart = exportPart.part(); const cvf::DrawableGeo* geo = dynamic_cast(cvfPart ? cvfPart->drawable() : nullptr); if (!geo) { return false; } if (geo->primitiveSetCount() != 1) { RiaLogging::debug("Only geometries with exactly one primitive set is supported"); return false; } const cvf::Vec3fArray* vertexArr = geo->vertexArray(); const cvf::PrimitiveSet* primSet = geo->primitiveSet(0); if (!vertexArr || !primSet || primSet->faceCount() == 0) { return false; } if (primSet->primitiveType() != cvf::PT_TRIANGLES) { RiaLogging::debug(QString("Currently only triangle primitive sets are supported (saw primitive type: %1)").arg(primSet->primitiveType())); return false; } mesh->verticesPerPrimitive = 3; // Possibly transform the vertices if (cvfPart->transform()) { const size_t vertexCount = vertexArr->size(); cvf::ref transVertexArr = new cvf::Vec3fArray(vertexArr->size()); cvf::Mat4f m = cvf::Mat4f(cvfPart->transform()->worldTransform()); for (size_t i = 0; i < vertexCount; i++) { transVertexArr->set(i, vertexArr->get(i).getTransformedPoint(m)); } mesh->vertexArr = transVertexArr.p(); } else { mesh->vertexArr = vertexArr; } cvf::UIntArray faceConn; const size_t faceCount = primSet->faceCount(); for (size_t iface = 0; iface < faceCount; iface++) { primSet->getFaceIndices(iface, &faceConn); //mesh->connArr.insert(mesh->connArr.end(), faceConn.begin(), faceConn.end()); // Reverse the winding const size_t numConn = faceConn.size(); for (size_t i = 0; i < numConn; i++) { mesh->connArr.push_back(faceConn[numConn - i - 1]); } } // !!!! // Experiment with texture fringes //if (geo->textureCoordArray()) //{ // cvf::Part* nonConstPart = const_cast(cvfPart); // cvf::Effect* eff = nonConstPart->effect(); // cvf::RenderStateTextureBindings* rsTexBindings = dynamic_cast(eff->renderStateOfType(cvf::RenderState::TEXTURE_BINDINGS)); // if (rsTexBindings && rsTexBindings->bindingCount() > 0) // { // cvf::TextureImage* texImg = rsTexBindings->texture(0)->image(); // if (texImg) // { // mesh->texCoordArr = geo->textureCoordArray(); // mesh->texImage = texImg; // } // } //} QString srcObjType = "unknown"; if (exportPart.sourceObjectType() == VdeExportPart::OBJ_TYPE_GRID) srcObjType = "grid"; else if (exportPart.sourceObjectType() == VdeExportPart::OBJ_TYPE_PIPE) srcObjType = "pipe"; mesh->meshSourceObjTypeStr = srcObjType; mesh->meshSourceObjName = exportPart.sourceObjectName(); mesh->color = exportPart.color(); mesh->opacity = exportPart.opacity(); return true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool VdeFileExporter::writeDataPacketToFile(int arrayId, const VdeArrayDataPacket& packet) const { const QString fileName = m_absOutputFolder + QString("/arrayData_%1.bin").arg(arrayId); QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { return false; } if (file.write(packet.fullPacketRawPtr(), packet.fullPacketSize()) == -1) { return false; } return false; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool VdeFileExporter::writeModelMetaJsonFile(const std::vector& meshArr, const std::vector& meshContentIdsArr, QString fileName) { QVariantList jsonMeshMetaList; for (size_t i = 0; i < meshArr.size(); i++) { const VdeMesh& mesh = meshArr[i]; const VdeMeshArrayIds& meshIds = meshContentIdsArr[i]; QMap jsonMeshMeta; jsonMeshMeta["meshSourceObjType"] = mesh.meshSourceObjTypeStr; jsonMeshMeta["meshSourceObjName"] = mesh.meshSourceObjName; jsonMeshMeta["verticesPerPrimitive"] = mesh.verticesPerPrimitive; jsonMeshMeta["vertexArrId"] = meshIds.vertexArrId; jsonMeshMeta["connArrId"] = meshIds.connArrId; if (meshIds.texCoordsArrId >= 0 && meshIds.texImageArrId >= 0) { jsonMeshMeta["texCoordsArrId"] = meshIds.texCoordsArrId; jsonMeshMeta["texImageArrId"] = meshIds.texImageArrId; } else { QMap jsonColor; jsonColor["r"] = mesh.color.r(); jsonColor["g"] = mesh.color.g(); jsonColor["b"] = mesh.color.b(); jsonMeshMeta["color"] = jsonColor; } jsonMeshMeta["opacity"] = mesh.opacity; jsonMeshMetaList.push_back(jsonMeshMeta); } QMap jsonModelMeta; jsonModelMeta["modelName"] = "ResInsightExport"; jsonModelMeta["meshArr"] = jsonMeshMetaList; ResInsightInternalJson::Json jsonCodec; const bool prettifyJson = true; QByteArray jsonStr = jsonCodec.encode(jsonModelMeta, prettifyJson).toLatin1(); QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { return false; } if (file.write(jsonStr) == -1) { return false; } return true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void VdeFileExporter::debugComparePackets(const VdeArrayDataPacket& packetA, const VdeArrayDataPacket& packetB) { CVF_ASSERT(packetA.elementCount() == packetB.elementCount()); CVF_ASSERT(packetA.elementSize() == packetB.elementSize()); CVF_ASSERT(packetA.elementType() == packetB.elementType()); const char* arrA = packetA.arrayData(); const char* arrB = packetB.arrayData(); for (size_t i = 0; i < packetA.elementCount(); i++) { CVF_ASSERT(arrA[i] == arrB[i]); } }