/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" #include "NwMaterialImport.h" //tv #include "TvMaterial.h" //nw #include "NwDatabase.h" #include "NwTexture.h" #include "NwColor.h" #include "Attribute/NwMaterialAttribute.h" #include "Attribute/NwGraphicMaterialAttribute.h" #include "Materials/NwTextureMapper.h" #include "NwHostAppServices.h" #include "Materials/NwMaterialElement.h" #include "Materials/NwAdvancedMaterial.h" #include "NwPathUtils.h" //raster #include "DynamicLinker.h" #include "RxRasterServices.h" static OdString nwSanitizePath(const OdString& path) { OdString sToFindSanitized = path; sToFindSanitized.replace('\\', '/'); // win to lin return sToFindSanitized; } static OdString nwExtractFileName(const OdString& path) { // get filename with extension OdString sToFindSanitized = nwSanitizePath(path); const int lastDelimiter = sToFindSanitized.reverseFind('/'); if (-1 == lastDelimiter) return path; // no delimiter return sToFindSanitized.mid(lastDelimiter + 1); } ///////////////////////////////////////////////// namespace NwMaterialImport { template OdTvMaterialColor getTvColorFromNwColor(const OdNwColor& nwClr) { OdTvMaterialColor tvMatClr(OdTvColorDef(nwClr.R() * 255.0, nwClr.G() * 255.0, nwClr.B() * 255.0)); tvMatClr.setMethod(clrMethod); return tvMatClr; } OdTvMaterialId OdNw2TvMaterialImport::importByAdvancedMaterial(const OdNwTexture* pTxt, OdNwDatabase* pNwDb) { OdTvMaterialId tvMaterialId = createTvMaterial(pTxt); if (tvMaterialId.isNull()) return tvMaterialId; OdTvMaterialPtr pTvMaterial = tvMaterialId.openObject(OdTv::kForWrite); pTvMaterial->setSupportNonTextureMode(false); auto pTvDb = m_tvDatabaseId.openObject(OdTv::kForWrite); auto pNwHostApp = pNwDb->appServices(); auto nwTxtMapper2TvTxtMapper = [pNwHostApp, pNwDb, this, &pTvDb](OdNwTextureMapper&& nwTxtMap, OdTvMaterialMap& tvMaterialMap) { OdTvResult rc = tvOk; OdResult resCode = eOk; if (pNwHostApp) { const OdString& sOrigPath = nwTxtMap.getPath(); OdTvTextureMapper tvTxtMap; if (!sOrigPath.isEmpty()) { tvTxtMap.setTransform(nwTxtMap.getTransform(m_nwCurPartUnits)); if (sOrigPath.find((OdChar)'.') > 0) { const OdString& sFName = nwExtractFileName(sOrigPath); OdTvRasterImageId rasterImageId = pTvDb->findRasterImage(sFName, &rc); if (rc != tvOk) { OdGiRasterImagePtr pRI = nwTxtMap.getRasterImage(&resCode); if (resCode == eOk && !pRI.isNull()) { OdString sFileNameBase, sFileExt; NwPathUtils::splitExt(sFName, sFileNameBase, sFileExt); if (m_getTempFilePath) { rasterImageId.setNull(); OdString sTempPath = m_getTempFilePath(sFileNameBase, sFileExt.isEmpty() ? OdString(OD_T(".bmp")) : sFileExt); if (!sTempPath.isEmpty()) { try { OdRxRasterServicesPtr pRasSvcs = ::odrxDynamicLinker()->loadApp(RX_RASTER_SERVICES_APPNAME); if (!pRasSvcs.isNull() && pRasSvcs->saveRasterImage(pRI, sTempPath)) { tvMaterialMap.setSourceFileName(sTempPath); } } catch (...) { } } } else { OdBinaryData bufData; bufData.resize(pRI->pixelHeight() * pRI->scanLineSize()); pRI->scanLines(const_cast(bufData.asArrayPtr()), 0, pRI->pixelHeight()); if (pRI->numColors() == 0) { OdTvRasterImage::Format riFrmt = OdTvRasterImage::Format::kRGB; if (pRI->pixelFormat().isRGBA()) riFrmt = OdTvRasterImage::kRGBA; else if (pRI->pixelFormat().isRGB()) riFrmt = OdTvRasterImage::kRGB; else if (pRI->pixelFormat().isBGRA()) riFrmt = OdTvRasterImage::kBGRA; else if (pRI->pixelFormat().is16bitBGR()) riFrmt = OdTvRasterImage::kBGR_16; else if (pRI->pixelFormat().isBGR()) riFrmt = OdTvRasterImage::kBGR; rasterImageId = pTvDb->createRasterImage(sFName, riFrmt, pRI->pixelWidth(), pRI->pixelHeight(), const_cast(bufData.asArrayPtr()), pRI->scanLinesAlignment(), &rc); } else if (pRI->numColors() == 2 && pRI->colorDepth() == 1) { ODCOLORREF color1 = pRI->color(0); ODCOLORREF color2 = pRI->color(1); bool bInverted = false; if (30 * ODGETRED(color1) + 59 * ODGETGREEN(color1) + 11 * ODGETBLUE(color1) > 30 * ODGETRED(color2) + 59 * ODGETGREEN(color2) + 11 * ODGETBLUE(color2)) bInverted = false; else bInverted = true; rasterImageId = pTvDb->createRasterImage(sFName, pRI->pixelWidth(), pRI->pixelHeight(), const_cast(bufData.asArrayPtr()), bInverted, pRI->scanLinesAlignment(), &rc); } else { OdTvRasterImage::Format riFrmt = OdTvRasterImage::Format::kRGB; if (pRI->pixelFormat().isRGBA()) riFrmt = OdTvRasterImage::kRGBA; else if (pRI->pixelFormat().isRGB()) riFrmt = OdTvRasterImage::kRGB; else if (pRI->pixelFormat().isBGRA()) riFrmt = OdTvRasterImage::kBGRA; else if (pRI->pixelFormat().is16bitBGR()) riFrmt = OdTvRasterImage::kBGR_16; else if (pRI->pixelFormat().isBGR()) riFrmt = OdTvRasterImage::kBGR; OdBinaryData bufPaletteData; bufPaletteData.resize(pRI->paletteDataSize()); pRI->paletteData(const_cast(bufPaletteData.asArrayPtr())); OdTvRasterImage::BitPerIndex bpi = OdTvRasterImage::kEightBits; if (pRI->colorDepth() != 8) bpi = OdTvRasterImage::kFourBits; rasterImageId = pTvDb->createRasterImage(sFName, riFrmt, pRI->paletteDataSize(), const_cast(bufPaletteData.asArrayPtr()), bpi, pRI->pixelWidth(), pRI->pixelHeight(), const_cast(bufData.asArrayPtr()), pRI->scanLinesAlignment(), &rc); } if (!rasterImageId.isNull()) tvMaterialMap.setSourceRasterImage(rasterImageId); } } } else { tvMaterialMap.setSourceRasterImage(rasterImageId); } if (tvMaterialMap.getSourceFileName().isEmpty() && rasterImageId.isNull()) { const OdString& sTextureFName = pNwHostApp->findFile(sOrigPath, pNwDb, OdDbBaseHostAppServices::kTextureMapFile); tvMaterialMap.setSourceFileName(sTextureFName); } } } tvMaterialMap.setMapper(tvTxtMap); } return rc; }; //diffuse { OdTvMaterialMap tvMaterialMap; auto dDifInt = pTxt->getDiffuseIntensity(); if (OdNonZero(dDifInt)) { OdNwTextureMapper nwTxtMap; if (pTxt->getMapper(NwTextureMapperType::kDiffuse, nwTxtMap) == eOk) { nwTxtMapper2TvTxtMapper(std::move(nwTxtMap), tvMaterialMap); tvMaterialMap.setBlendFactor(dDifInt); } } pTvMaterial->setDiffuse(getTvColorFromNwColor(pTxt->getDiffuse()), tvMaterialMap); } //opacity { OdTvMaterialMap tvMaterialMap; { OdNwTextureMapper nwTxtMap; if (pTxt->getMapper(NwTextureMapperType::kOpacity, nwTxtMap) == eOk) nwTxtMapper2TvTxtMapper(std::move(nwTxtMap), tvMaterialMap); } auto fRalMatTrcy = pTxt->getTransparency(); if (OdGreater(fRalMatTrcy, 1.f, 1.e-6)) pTvMaterial->setOpacity(1.f - fRalMatTrcy / 100.f, &tvMaterialMap); else pTvMaterial->setOpacity(1.f - fRalMatTrcy, &tvMaterialMap); } //ambient pTvMaterial->setAmbient(getTvColorFromNwColor(pTxt->getAmbient())); //specular { pTvMaterial->setSpecular(getTvColorFromNwColor(pTxt->getSpecular()), pTxt->getShininess()); auto reflectivity = pTxt->getReflectIntensity(); if (OdPositive(reflectivity)) pTvMaterial->setReflectivity(reflectivity, OdTvMaterial::kReflectTexture, m_sReflectionEnvPath); } OdTvMaterialMap map; pTvMaterial->setEmission(getTvColorFromNwColor(pTxt->getEmissive()), map); //bump { OdTvMaterialMap tvMaterialMap; { OdNwTextureMapper nwTxtMap; if (pTxt->getMapper(NwTextureMapperType::kBump, nwTxtMap) == eOk) { nwTxtMapper2TvTxtMapper(std::move(nwTxtMap), tvMaterialMap); tvMaterialMap.setBlendFactor(pTxt->getBumpAmount()); } } pTvMaterial->setBump(tvMaterialMap); } //pattern { OdTvMaterialMap tvMaterialMap; { OdNwTextureMapper nwTxtMap; if (pTxt->getMapper(NwTextureMapperType::kPattern, nwTxtMap) == eOk) { nwTxtMapper2TvTxtMapper(std::move(nwTxtMap), tvMaterialMap); tvMaterialMap.setBlendFactor(pTxt->getPatternAmount()); } } pTvMaterial->setNormalMap(tvMaterialMap, OdTvMaterial::kReliefPattern, pTxt->getPatternAmount()); } //cutout { OdTvMaterialMap tvMaterialMap; { OdNwTextureMapper nwTxtMap; if (pTxt->getMapper(NwTextureMapperType::kCutout, nwTxtMap) == eOk) nwTxtMapper2TvTxtMapper(std::move(nwTxtMap), tvMaterialMap); } pTvMaterial->setCutouts(tvMaterialMap); } //tint OdNwColor tempNwColor; if (pTxt->getTint(tempNwColor) == eOk) pTvMaterial->setTint(getTvColorFromNwColor(tempNwColor), pTxt->IsUseTintColor()); return tvMaterialId; } OdTvMaterialId OdNw2TvMaterialImport::importMaterial(const OdNwObjectId& nwRealisticMtlId, const OdNwObjectId& nwShadedMtlId, OdTvColorDef& entClr) { OdTvResult rc = tvOk; OdTvMaterialId tvMaterialId; OdNwTexturePtr pTxt = nwRealisticMtlId.openObject(); const OdGUID& txtBundleGUID = pTxt->getBundleGUID(); if (txtBundleGUID == OdGUID::kNull) { tvMaterialId = importByAdvancedMaterial(pTxt.get(), nwRealisticMtlId.database()); OdTvMaterialPtr pTvMaterial = tvMaterialId.openObject(OdTv::kForWrite); if (nwShadedMtlId) { pTvMaterial->setSupportNonTextureMode(true); OdNwMaterialPtr pNwShadedMtl = nwShadedMtlId.safeOpenObject(); //diffuse { auto diffuse = pNwShadedMtl->getDiffuse(); entClr = OdTvColorDef(255.0 * diffuse.R(), 255.0 * diffuse.G(), 255.0 * diffuse.B()); pTvMaterial->setSecondaryDiffuse(getTvColorFromNwColor(diffuse)); } //opacity auto dMatTrcy = pNwShadedMtl->getTransparency(); if (OdGreater(dMatTrcy, 1.f, 1.e-6)) pTvMaterial->setSecondaryOpacity(1.f - dMatTrcy / 100.f); else pTvMaterial->setSecondaryOpacity(1.f - dMatTrcy); //ambient pTvMaterial->setSecondaryAmbient(getTvColorFromNwColor(pNwShadedMtl->getAmbient())); //specular pTvMaterial->setSecondarySpecular(getTvColorFromNwColor(pNwShadedMtl->getSpecular())); } } else { auto resFndAdvMat = m_mNwAdvMatCache.find(txtBundleGUID.toString()); if (resFndAdvMat != m_mNwAdvMatCache.end()) { if (nwShadedMtlId) { //if not find - check simpl material attribute traits - if there is already created material with such data auto resFndSimpleMat = resFndAdvMat->second.m_mNwSimplMatCache.find(Nw2TvSimpleMatCache(nwShadedMtlId)); if (resFndSimpleMat == resFndAdvMat->second.m_mNwSimplMatCache.end()) { OdNwMaterialPtr pNwShaddedMat = nwShadedMtlId.openObject(); if (resFndAdvMat->second.m_bIsTvMatDefault) { //default mat cond - combine with simple material setSimpleMaterialAsShadded(resFndAdvMat->second.m_tvMatId, pNwShaddedMat.get()); resFndAdvMat->second.m_bIsTvMatDefault = false; tvMaterialId = resFndAdvMat->second.m_tvMatId; resFndAdvMat->second.m_mNwSimplMatCache.insert({ Nw2TvSimpleMatCache(nwShadedMtlId), tvMaterialId }); } else { tvMaterialId = copyAndSetMaterialShadded(resFndAdvMat->second.m_tvMatId, pNwShaddedMat.get()); resFndAdvMat->second.m_mNwSimplMatCache.insert({ Nw2TvSimpleMatCache(nwShadedMtlId), tvMaterialId }); } } else { tvMaterialId = resFndSimpleMat->second; } auto pTvMat = tvMaterialId.openObject(); if (!pTvMat.isNull() && pTvMat->getSupportNonTextureMode()) entClr = pTvMat->getSecondaryDiffuse().getColor(); } else { if (resFndAdvMat->second.m_bIsTvMatDefault) { tvMaterialId = resFndAdvMat->second.m_tvMatId; } else { //default mat cond - combine with simple material tvMaterialId = copyAndSetDefaultShadded(resFndAdvMat->second.m_tvMatId); resFndAdvMat->second.m_bIsTvMatDefault = true; resFndAdvMat->second.m_tvMatId = tvMaterialId; } } } else { tvMaterialId = importByAdvancedMaterial(pTxt.get(), nwRealisticMtlId.database()); auto resIns = m_mNwAdvMatCache.insert({ txtBundleGUID.toString(), { true, tvMaterialId, {} } }); OdTvMaterialPtr pTvMaterial = tvMaterialId.openObject(OdTv::kForWrite); if (nwShadedMtlId) { pTvMaterial->setSupportNonTextureMode(true); OdNwMaterialPtr pNwShadedMtl = nwShadedMtlId.safeOpenObject(); //diffuse { auto diffuse = pNwShadedMtl->getDiffuse(); entClr = OdTvColorDef(255.0 * diffuse.R(), 255.0 * diffuse.G(), 255.0 * diffuse.B()); pTvMaterial->setSecondaryDiffuse(getTvColorFromNwColor(diffuse)); } //opacity auto dMatTrcy = pNwShadedMtl->getTransparency(); if (OdGreater(dMatTrcy, 1.f, 1.e-6)) pTvMaterial->setSecondaryOpacity(1.f - dMatTrcy / 100.f); else pTvMaterial->setSecondaryOpacity(1.f - dMatTrcy); //ambient pTvMaterial->setSecondaryAmbient(getTvColorFromNwColor(pNwShadedMtl->getAmbient())); //specular pTvMaterial->setSecondarySpecular(getTvColorFromNwColor(pNwShadedMtl->getSpecular())); resIns.first->second.m_bIsTvMatDefault = false; resIns.first->second.m_mNwSimplMatCache.insert({ Nw2TvSimpleMatCache(nwShadedMtlId), tvMaterialId }); } } } return tvMaterialId; } template OdTvMaterialId OdNw2TvMaterialImport::importMaterial(const T* pNwSimpleMat, OdTvColorDef& tvEntClr) { if (!pNwSimpleMat) return OdTvMaterialId(); OdTvResult rc = tvOk; OdTvMaterialId tvMaterialId = createTvMaterial(pNwSimpleMat); if (tvMaterialId.isNull()) return tvMaterialId; OdTvMaterialPtr pTvMaterial = tvMaterialId.openObject(OdTv::kForWrite); OdNwColor diffuse = pNwSimpleMat->getDiffuse(); tvEntClr = OdTvColorDef(255.0 * diffuse.R(), 255.0 * diffuse.G(), 255.0 * diffuse.B()); pTvMaterial->setSupportNonTextureMode(false); //diffuse OdTvMaterialMap tvMaterialMap; pTvMaterial->setDiffuse(getTvColorFromNwColor(diffuse), tvMaterialMap); //opacity double trcy = pNwSimpleMat->getTransparency(); if (OdGreater(trcy, 1.)) pTvMaterial->setOpacity(1. - trcy / 100., &tvMaterialMap); else pTvMaterial->setOpacity(1. - trcy, &tvMaterialMap); //ambient pTvMaterial->setAmbient(getTvColorFromNwColor(pNwSimpleMat->getAmbient())); //specular double dShinines = pNwSimpleMat->getShininess(); auto nwClrSpec = pNwSimpleMat->getSpecular(); //if simple specular color has black color - then this mean that there is no neeed for specular while visualization, need to disable it by - set black color with override method if (OdZero(nwClrSpec.R()) && OdZero(nwClrSpec.G()) && OdZero(nwClrSpec.B())) { //material attribute contain 0. value for shinines, but in navis and end fragment's material it will be 0.00001 pTvMaterial->setSpecular(getTvColorFromNwColor(nwClrSpec), OdZero(dShinines) ? 0.00001 : dShinines); } else { //material attribute contain 0. value for shinines, but in navis and end fragment's material it will be 0.00001 pTvMaterial->setSpecular(getTvColorFromNwColor(nwClrSpec), OdZero(dShinines) ? 0.00001 : dShinines); } pTvMaterial->setEmission(getTvColorFromNwColor(pNwSimpleMat->getEmissive()), tvMaterialMap); return tvMaterialId; } void OdNw2TvMaterialImport::importMaterialElement() { //if material element is empty - just return if (!m_nwMatElId) return; OdNwSavedItemsElementPtr pSIEl = m_nwMatElId.openObject(); if (!pSIEl.isNull()) { OdNwDatabase* pNwDb = m_nwMatElId.database(); OdNwObjectIdArray aSIs; if (pSIEl->getSavedItems(aSIs) == eOk) { for (auto& siId : aSIs) { OdNwAdvancedMaterialPtr pAdvMat = siId.openObject(); if (!pAdvMat.isNull()) { auto pTxtDelegate = OdNwTexture::cast(pAdvMat); if (!pTxtDelegate.isNull()) { OdTvMaterialId tvMaterialId = importByAdvancedMaterial(pTxtDelegate.get(), pNwDb); if (tvMaterialId.isNull()) continue; m_mNwAdvMatCache.insert({ pTxtDelegate->getBundleGUID().toString(), { true, tvMaterialId, {} } }); } } } } } //set material element to null for except import of material element more then one time m_nwMatElId.setNull(); } template OdTvMaterialId OdNw2TvMaterialImport::copyAndSetMaterialShadded(const OdTvMaterialId& tvMatId, const T* pNwSimpleMat) { auto tvNewMatId = copyMaterial(tvMatId); if (!tvNewMatId.isNull()) setSimpleMaterialAsShadded(tvNewMatId, pNwSimpleMat); return tvNewMatId; } OdTvMaterialId OdNw2TvMaterialImport::copyAndSetDefaultShadded(const OdTvMaterialId& tvMatId) { auto tvNewMatId = copyMaterial(tvMatId); if (!tvNewMatId.isNull()) { OdTvMaterialPtr pTvMat = tvNewMatId.openObject(OdTv::kForWrite); pTvMat->setSupportNonTextureMode(true); OdTvMaterialColor tvMatClr = m_defaultEntColor; tvMatClr.setMethod(OdTvMaterialColor::kInherit); pTvMat->setSecondaryDiffuse(tvMatClr); pTvMat->setSecondaryOpacity(0.); pTvMat->setSecondarySpecular(tvMatClr); pTvMat->setSecondaryAmbient(tvMatClr); } return tvNewMatId; } OdTvMaterialId OdNw2TvMaterialImport::copyMaterial(const OdTvMaterialId& tvMatId) { OdTvDatabasePtr pTvDb = m_tvDatabaseId.openObject(OdTv::kForWrite); OdTvMaterialPtr pTvMat = tvMatId.openObject(OdTv::kForWrite); OdTvMaterialId newTvMatId = createTvMaterial(pTvMat->getName() + odrxSystemServices()->createGuid()); OdTvMaterialPtr pNewTvMat = newTvMatId.openObject(OdTv::kForWrite); //change names { OdString sName = pTvMat->getName(); pTvMat->setName(pNewTvMat->getName()); pNewTvMat->setName(sName); } //copy all data { pNewTvMat->setSupportNonTextureMode(pTvMat->getSupportNonTextureMode()); OdTvMaterialMap tvMaterialMap; OdTvMaterialColor tvMaterialColor; //diffuse { pTvMat->getDiffuse(tvMaterialColor, tvMaterialMap); pNewTvMat->setDiffuse(tvMaterialColor, tvMaterialMap); } //opacity { double dOpacity = 0.; pTvMat->getOpacity(dOpacity, tvMaterialMap); pNewTvMat->setOpacity(dOpacity, &tvMaterialMap); } //ambient { pNewTvMat->setAmbient(pTvMat->getAmbient()); } //specular { double dGlossFactor = 0.; pTvMat->getSpecular(tvMaterialColor, dGlossFactor); pNewTvMat->setSpecular(tvMaterialColor, dGlossFactor); double dRefl = 0; OdTvMaterial::ReflectivityType reflType; pTvMat->getReflectivity(dRefl, reflType); pNewTvMat->setReflectivity(dRefl, reflType, m_sReflectionEnvPath); } //emission { tvMaterialColor = pTvMat->getEmission(tvMaterialMap); pNewTvMat->setEmission(tvMaterialColor, tvMaterialMap); } //bump { pTvMat->getBump(tvMaterialMap); pNewTvMat->setBump(tvMaterialMap); } //pattern { OdTvMaterial::NormalMapMethod patterMethod; double patternStrength = 0.; pTvMat->getNormalMap(tvMaterialMap, patterMethod, patternStrength); pNewTvMat->setNormalMap(tvMaterialMap, patterMethod, patternStrength); } //cutout { pNewTvMat->setCutouts(pTvMat->getCutouts()); } //tint { bool isTintEnable = pTvMat->getTint(tvMaterialColor); pNewTvMat->setTint(tvMaterialColor, isTintEnable); } } return newTvMatId; } template void OdNw2TvMaterialImport::setSimpleMaterialAsShadded(const OdTvMaterialId& tvMatId, const T* pNwSimpleMat) { OdTvMaterialPtr pTvMat = tvMatId.openObject(OdTv::kForWrite); pTvMat->setSupportNonTextureMode(true); //diffuse pTvMat->setSecondaryDiffuse(getTvColorFromNwColor(pNwSimpleMat->getDiffuse())); //opacity auto trcy = pNwSimpleMat->getTransparency(); if (OdGreater(trcy, 1.f, 1.e-6)) pTvMat->setSecondaryOpacity(1.f - trcy / 100.f); else pTvMat->setSecondaryOpacity(1.f - trcy); //ambient pTvMat->setSecondaryAmbient(getTvColorFromNwColor(pNwSimpleMat->getAmbient())); //specular pTvMat->setSecondarySpecular(getTvColorFromNwColor(pNwSimpleMat->getSpecular())); } OdGUID OdNw2TvMaterialImport::getGUIDFromGraphMatAttr(const OdNwGraphicMaterialAttribute* pGrMat) { auto resFnd = m_mAdvMatAttrIds.find(pGrMat); if (resFnd == m_mAdvMatAttrIds.end()) { const OdGUID& resGUID = pGrMat->getBundleGUID(); m_mAdvMatAttrIds.insert({ pGrMat, resGUID }); return resGUID; } else return resFnd->second; } //sfinae common implementation for getting simple material traits from material pointer - OdNwMaterial/OdNwGraphicMaterialAttribute //ambient template typename std::enable_if::value, OdNwColor>::type getAmbient(const T* pMat) { return pMat->getAmbient(); } template typename std::enable_if::value, OdNwColor>::type getAmbient(const T* pMat) { return pMat->getAmbient(); } //diffuse template typename std::enable_if::value, OdNwColor>::type getDiffuse(const T* pMat) { return pMat->getDiffuse(); } template typename std::enable_if::value, OdNwColor>::type getDiffuse(const T* pMat) { return pMat->getDiffuse(); } //specular template typename std::enable_if::value, OdNwColor>::type getSpecular(const T* pMat) { return pMat->getSpecular(); } template typename std::enable_if::value, OdNwColor>::type getSpecular(const T* pMat) { return pMat->getSpecular(); } //emissive template typename std::enable_if::value, OdNwColor>::type getEmissive(const T* pMat) { return pMat->getEmissive(); } template typename std::enable_if::value, OdNwColor>::type getEmissive(const T* pMat) { return pMat->getEmissive(); } //shinines template typename std::enable_if::value, float>::type getShininess(const T* pMat) { return pMat->getShininess(); } template typename std::enable_if::value, float>::type getShininess(const T* pMat) { return static_cast(pMat->getShininess()); } //transparency template typename std::enable_if::value, float>::type getTransparency(const T* pMat) { return pMat->getTransparency(); } template typename std::enable_if::value, float>::type getTransparency(const T* pMat) { return static_cast(pMat->getTransparency()); } bool cmprNwColor(const OdNwColor& nwColor1, const OdNwColor& nwColor2) { return nwColor1.R() == nwColor2.R() && nwColor1.G() == nwColor2.G() && nwColor1.B() == nwColor2.B() && nwColor1.A() == nwColor2.A(); } template bool cmprMaterials(const T1* pMat1, const T2* pMat2) { //material attribute contain 0. value for shinines, but in navis and end fragment's material it will be 0.00001 return (OdEqual(getShininess(pMat1), getShininess(pMat2)) || OdEqual(getShininess(pMat1), 0.00001) && OdEqual(getShininess(pMat2), 0.)) && //because transparency from fragment's material is float and from material attribute is double value - convert both argeuments to float before compare OdEqual(getTransparency(pMat1), getTransparency(pMat2)) && cmprNwColor(getDiffuse(pMat1), getDiffuse(pMat2)) && cmprNwColor(getAmbient(pMat1), getAmbient(pMat2)) && cmprNwColor(getSpecular(pMat1), getSpecular(pMat2)) && cmprNwColor(getEmissive(pMat1), getEmissive(pMat2)); } bool compareMaterial(const OdNwObjectId& nwShadedMtlId, const OdNwMaterialAttribute* pNwMatAttr) { OdNwMaterialPtr pNwMat = nwShadedMtlId.openObject(); return cmprMaterials(pNwMat.get(), pNwMatAttr); } ///////////////////////////////////////////////////////////// Nw2TvSimpleMatCache::Nw2TvSimpleMatCache(const OdNwObjectId& nwMaterialId) : m_bIsAttr(false) , m_material(nwMaterialId) { } Nw2TvSimpleMatCache::Nw2TvSimpleMatCache(const OdNwMaterialAttribute* pMaterialAttr) : m_bIsAttr(true) , m_material(pMaterialAttr) { } bool Nw2TvSimpleMatCache::operator==(const Nw2TvSimpleMatCache& other) const { if (m_bIsAttr && other.m_bIsAttr) { return cmprMaterials(m_material.m_pMaterialAttr, other.m_material.m_pMaterialAttr); } else if (m_bIsAttr) { return compareMaterial(other.m_material.m_nwMaterialId, m_material.m_pMaterialAttr); } else if (other.m_bIsAttr) { return compareMaterial(m_material.m_nwMaterialId, other.m_material.m_pMaterialAttr); } else { OdNwMaterialPtr pMat1 = m_material.m_nwMaterialId.openObject(); OdNwMaterialPtr pMat2 = other.m_material.m_nwMaterialId.openObject(); return cmprMaterials(pMat1.get(), pMat2.get()); } } OdUInt32 Nw2TvSimpleMatCache::getAmbient() const { return m_bIsAttr ? m_material.m_pMaterialAttr->getAmbient().ToColor() : OdNwMaterial::cast(m_material.m_nwMaterialId.openObject())->getAmbient().ToColor(); } OdUInt32 Nw2TvSimpleMatCache::getDiffuse() const { return m_bIsAttr ? m_material.m_pMaterialAttr->getDiffuse().ToColor() : OdNwMaterial::cast(m_material.m_nwMaterialId.openObject())->getDiffuse().ToColor(); } OdUInt32 Nw2TvSimpleMatCache::getEmissive() const { return m_bIsAttr ? m_material.m_pMaterialAttr->getEmissive().ToColor() : OdNwMaterial::cast(m_material.m_nwMaterialId.openObject())->getEmissive().ToColor(); } OdUInt32 Nw2TvSimpleMatCache::getSpecular() const { return m_bIsAttr ? m_material.m_pMaterialAttr->getSpecular().ToColor() : OdNwMaterial::cast(m_material.m_nwMaterialId.openObject())->getSpecular().ToColor(); } float Nw2TvSimpleMatCache::getShininess() const { return m_bIsAttr ? m_material.m_pMaterialAttr->getShininess() : OdNwMaterial::cast(m_material.m_nwMaterialId.openObject())->getShininess(); } float Nw2TvSimpleMatCache::getTransparency() const { return m_bIsAttr ? m_material.m_pMaterialAttr->getTransparency() : OdNwMaterial::cast(m_material.m_nwMaterialId.openObject())->getTransparency(); } /////////////////////////////////////////////////////// Nw2TvMatAttributes::Nw2TvMatAttributes(const OdNwMaterialAttribute* pNwMatAttr, const OdNwGraphicMaterialAttribute* pNwGrMatAttr) : m_pNwMatAttr(pNwMatAttr) , m_pNwGrMatAttr(pNwGrMatAttr) {} bool Nw2TvMatAttributes::operator==(const Nw2TvMatAttributes& other) const { return other.getNwMatAttr() == getNwMatAttr() && other.getNwGrMatAttr() == getNwGrMatAttr(); } /////////////////////////////////////////////////////// OdNw2TvMaterialImport::OdNw2TvMaterialImport(const OdTvDatabaseId& tvDatabaseId, const OdNwObjectId& nwMatElId, NwModelUnits::Enum nwCurPartUnits, const OdTvColorDef& tvDefClr, const OdString& sReflEnv, std::function getTempFilePath) : m_tvDatabaseId(tvDatabaseId) , m_nwMatElId(nwMatElId) , m_nwCurPartUnits(nwCurPartUnits) , m_defaultEntColor(tvDefClr) , m_sReflectionEnvPath(sReflEnv) , m_getTempFilePath(getTempFilePath) {} bool OdNw2TvMaterialImport::checkAdvancedMaterialGUID(const OdNwGraphicMaterialAttribute* pGrMat) { return m_mNwAdvMatCache.find(getGUIDFromGraphMatAttr(pGrMat).toString()) != m_mNwAdvMatCache.end(); } OdTvMaterialId OdNw2TvMaterialImport::getMaterial(const OdNwObjectId& nwMtlId, OdTvColorDef& entClr) { importMaterialElement(); OdTvMaterialId tvMatId; auto resFnd = m_mNwMatCache2TvMat.find(nwMtlId); if (resFnd == m_mNwMatCache2TvMat.end()) { //simple material case auto resFndSimpleMat = m_mNwSimplMatCache.find(Nw2TvSimpleMatCache(nwMtlId)); if (resFndSimpleMat == m_mNwSimplMatCache.end()) { OdNwMaterialPtr pNwMat = nwMtlId.openObject(); tvMatId = importMaterial(pNwMat.get(), entClr); m_mNwSimplMatCache.insert({ Nw2TvSimpleMatCache(nwMtlId), tvMatId }); } else { tvMatId = resFndSimpleMat->second; //get enitity color from mat { OdTvMaterialColor tvMatClr; OdTvMaterialMap tvMatMap; tvMatId.openObject()->getDiffuse(tvMatClr, tvMatMap); entClr = tvMatClr.getColor(); } } m_mNwMatCache2TvMat.insert({ nwMtlId , tvMatId }); } else { tvMatId = resFnd->second; //get enitity color from mat { OdTvMaterialColor tvMatClr; OdTvMaterialMap tvMatMap; tvMatId.openObject()->getDiffuse(tvMatClr, tvMatMap); entClr = tvMatClr.getColor(); } } return tvMatId; } OdTvMaterialId OdNw2TvMaterialImport::getMaterial(const OdNwObjectId& nwRealisticMtlId, const OdNwObjectId& nwShadedMtlId, OdTvColorDef& entClr) { importMaterialElement(); OdTvMaterialId tvMatId; auto resFnd = m_mNwMatCache2TvMat.find(nwRealisticMtlId); if (resFnd == m_mNwMatCache2TvMat.end()) { tvMatId = importMaterial(nwRealisticMtlId, nwShadedMtlId, entClr); m_mNwMatCache2TvMat.insert({ nwRealisticMtlId , tvMatId }); } else { tvMatId = resFnd->second; auto pTvMat = tvMatId.openObject(); //get enitity color from mat if (pTvMat->getSupportNonTextureMode()) entClr = pTvMat->getSecondaryDiffuse().getColor(); } return tvMatId; } OdTvMaterialId OdNw2TvMaterialImport::getMaterial(const OdNwMaterialAttribute* pNwMatAttr, const OdNwGraphicMaterialAttribute* pNwGraphMatAttr) { importMaterialElement(); OdTvMaterialId tvMatId; //check if there is already created tv materail for pair OdNwMaterialAttribute-OdNwGraphicMaterialAttribute auto resFndTvMat = m_mNwMatAttr2TvMat.find({ pNwMatAttr, pNwGraphMatAttr }); if (resFndTvMat == m_mNwMatAttr2TvMat.end()) { //if there is set only simple mat attribute if (!pNwGraphMatAttr) { if (pNwMatAttr) { //if not find - check simpl material attribute traits - if there is already created material with such data auto resFndSimpleMat = m_mNwSimplMatCache.find(Nw2TvSimpleMatCache(pNwMatAttr)); if (resFndSimpleMat == m_mNwSimplMatCache.end()) { OdTvColorDef tvClrEnt; tvMatId = importMaterial(pNwMatAttr, tvClrEnt); m_mNwSimplMatCache.insert({ Nw2TvSimpleMatCache(pNwMatAttr), tvMatId }); } else { tvMatId = resFndSimpleMat->second; } m_mNwMatAttr2TvMat.insert({ { pNwMatAttr, nullptr } , tvMatId }); } } else { const OdGUID& bundleGUID = pNwGraphMatAttr->getBundleGUID(); auto resFndAdvMat = m_mNwAdvMatCache.find(bundleGUID.toString()); if (resFndAdvMat == m_mNwAdvMatCache.end()) { //if there is no already created advanced material by bundle - then skip material import on this level } else { if (pNwMatAttr) { //if not find - check simpl material attribute traits - if there is already created material with such data auto resFndSimpleMat = resFndAdvMat->second.m_mNwSimplMatCache.find(Nw2TvSimpleMatCache(pNwMatAttr)); if (resFndSimpleMat == resFndAdvMat->second.m_mNwSimplMatCache.end()) { if (resFndAdvMat->second.m_bIsTvMatDefault) { //default mat cond - combine with simple material setSimpleMaterialAsShadded(resFndAdvMat->second.m_tvMatId, pNwMatAttr); resFndAdvMat->second.m_bIsTvMatDefault = false; tvMatId = resFndAdvMat->second.m_tvMatId; } else { tvMatId = copyAndSetMaterialShadded(resFndAdvMat->second.m_tvMatId, pNwMatAttr); } resFndAdvMat->second.m_mNwSimplMatCache.insert({ Nw2TvSimpleMatCache(pNwMatAttr), tvMatId }); } else { tvMatId = resFndSimpleMat->second; } } else { //is tv mat has only adv mat properties if (resFndAdvMat->second.m_bIsTvMatDefault) { tvMatId = resFndAdvMat->second.m_tvMatId; } else { //default mat cond - combine with simple material tvMatId = copyAndSetDefaultShadded(resFndAdvMat->second.m_tvMatId); resFndAdvMat->second.m_bIsTvMatDefault = true; resFndAdvMat->second.m_tvMatId = tvMatId; } } m_mNwMatAttr2TvMat.insert({ { pNwMatAttr, pNwGraphMatAttr } , tvMatId }); } } } else { tvMatId = resFndTvMat->second; } return tvMatId; } OdNw2TvMaterialImport::NwMatCompareState OdNw2TvMaterialImport::isEqual(const OdNwObjectId& nwShadedMtlId, const OdNwMaterialAttribute* pNwMatAttr, OdTvColorDef& tvEntClr, OdTvTransparencyDef& tvEntTrcy) { OdNwMaterialPtr pNwShadedMat = nwShadedMtlId.openObject(); OdNwMaterial* pNwShadedMatRaw = pNwShadedMat.get(); //material attribute contain 0. value for shinines, but in navis and end fragment's material it will be 0.00001 if (OdEqual(getShininess(pNwShadedMatRaw), getShininess(pNwMatAttr)) || OdEqual(getShininess(pNwShadedMatRaw), 0.00001) && OdEqual(getShininess(pNwMatAttr), 0.) && cmprNwColor(getAmbient(pNwShadedMatRaw), getAmbient(pNwMatAttr)) && cmprNwColor(getSpecular(pNwShadedMatRaw), getSpecular(pNwMatAttr)) && cmprNwColor(getEmissive(pNwShadedMatRaw), getEmissive(pNwMatAttr))) { auto nwShaddedTrcy = getTransparency(pNwShadedMatRaw); //because transparency from fragment's material is float and from material attribute is double value - convert both argeuments to float before compare if (OdEqual(nwShaddedTrcy, getTransparency(pNwMatAttr)) && cmprNwColor(getDiffuse(pNwShadedMatRaw), getDiffuse(pNwMatAttr))) { auto diffuse = getDiffuse(pNwShadedMatRaw); tvEntClr.setColor(255.0 * diffuse.R(), 255.0 * diffuse.G(), 255.0 * diffuse.B()); return NwMatCompareState::kIsEqual; } else { auto diffuse = getDiffuse(pNwShadedMatRaw); tvEntClr.setColor(255.0 * diffuse.R(), 255.0 * diffuse.G(), 255.0 * diffuse.B()); if (OdGreater(nwShaddedTrcy, 1.)) tvEntTrcy.setValue(nwShaddedTrcy/100.); else tvEntTrcy.setValue(nwShaddedTrcy); return NwMatCompareState::kIsEqaulWithOverrides; } } else { return NwMatCompareState::kIsNotEqual; } } bool OdNw2TvMaterialImport::isEqual(const OdNwObjectId& nwMatId, const OdNwGraphicMaterialAttribute* pNwGraphMatAttr) { auto pNwObj = nwMatId.openObject(); if (pNwObj->isA() != OdNwTexture::desc()) return false; OdNwTexturePtr pNwRealisticMat = pNwObj; return pNwRealisticMat->getBundleGUID() == getGUIDFromGraphMatAttr(pNwGraphMatAttr); } bool OdNw2TvMaterialImport::isEqual(const OdNwGraphicMaterialAttribute* pGrMat1, const OdNwGraphicMaterialAttribute* pGrMat2) { //this is the same objects if (pGrMat1 == pGrMat2) return true; else { return getGUIDFromGraphMatAttr(pGrMat1) == getGUIDFromGraphMatAttr(pGrMat2); } } OdTvMaterialId OdNw2TvMaterialImport::createTvMaterial(const OdString& sMatName) { OdTvDatabasePtr pTvDb = m_tvDatabaseId.openObject(OdTv::kForWrite); OdTvResult rc = tvOk; auto tvMaterialId = pTvDb->createMaterial(sMatName, &rc); if (rc == tvAlreadyExistSameName || rc == tvForbiddenName) tvMaterialId = pTvDb->createMaterial(sMatName + odrxSystemServices()->createGuid(), &rc); return tvMaterialId; } template typename std::enable_if::value || std::is_same::value, OdString>::type getMatName(const T* pNwMat) { return pNwMat->getDisplayName(); } template typename std::enable_if::value || std::is_same::value, OdString>::type getMatName(const T* pNwMat) { return pNwMat->getDisplayName(); } template constexpr typename std::enable_if::value, OdString>::type getDefMatName() { return OD_T("GeneratedMaterialAttribute_"); } template constexpr typename std::enable_if::value, OdString>::type getDefMatName() { return OD_T("GeneratedGraphicMaterialAttribute_"); } template constexpr typename std::enable_if::value, OdString>::type getDefMatName() { return OD_T("GeneratedMaterial_"); } template constexpr typename std::enable_if::value, OdString>::type getDefMatName() { return OD_T("GeneratedTexture_"); } template OdTvMaterialId OdNw2TvMaterialImport::createTvMaterial(const T* pNwMat) { //get material name auto sMatName = getMatName(pNwMat); if (sMatName == OD_T("IfcOpeningElement")) int i = 1; if (sMatName.isEmpty()) sMatName = getDefMatName() + odrxSystemServices()->createGuid(); else { if (m_mPossibleMatNames.find(sMatName) != m_mPossibleMatNames.end()) sMatName = sMatName + odrxSystemServices()->createGuid(); else m_mPossibleMatNames.insert(sMatName); } return createTvMaterial(sMatName); } }