From 30804b42323ac6005c28ecc06af82070b45504a0 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 8 Dec 2013 09:45:14 +0000 Subject: [PATCH] Support for surface styles, Multi/Sub-Object materials and material indices in the 3ds max importer --- src/ifcmax/IfcMax.cpp | 201 ++++++++++++++++++++++++++------------ src/ifcmax/MaxMaterials.h | 48 --------- 2 files changed, 139 insertions(+), 110 deletions(-) delete mode 100644 src/ifcmax/MaxMaterials.h diff --git a/src/ifcmax/IfcMax.cpp b/src/ifcmax/IfcMax.cpp index d251a10928..49b3c61bab 100644 --- a/src/ifcmax/IfcMax.cpp +++ b/src/ifcmax/IfcMax.cpp @@ -22,9 +22,10 @@ #include #include "../ifcmax/IfcMax.h" -#include "../ifcmax/MaxMaterials.h" #include "../ifcgeom/IfcGeomObjects.h" +static const int NUM_MATERIAL_SLOTS = 24; + int controlsInit = false; BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) { @@ -101,6 +102,102 @@ void IFCImp::ShowAbout(HWND hWnd) {} DWORD WINAPI fn(LPVOID arg) { return 0; } +#if MAX_RELEASE > 14000 +# define S(x) (TSTR::FromCStr(x.c_str())) +#elif defined(_UNICODE) +# define S(x) (WStr(x.c_str())) +#else +# define S(x) (CStr(x.c_str())) +#endif + +Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) { + const int mat_index = library->FindMtlByName(S(material_name)); + Mtl* m = 0; + if (mat_index != -1) { + m = static_cast((*library)[mat_index]); + } + return m; +} + +Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const IfcGeomObjects::Material& material) { + Mtl* m = FindMaterialByName(library, material.name()); + if (m == 0) { + StdMat2* stdm = NewDefaultStdMat(); + const TimeValue t = -1; + if (material.hasDiffuse()) { + const double* diffuse = material.diffuse(); + stdm->SetDiffuse(Color(diffuse[0], diffuse[1], diffuse[2]),t); + } + if (material.hasSpecular()) { + const double* specular = material.specular(); + stdm->SetSpecular(Color(specular[0], specular[1], specular[2]),t); + } + if (material.hasSpecularity()) { + stdm->SetShininess(material.specularity(), t); + } + if (material.hasTransparency()) { + stdm->SetOpacity(1.0 - material.transparency(), t); + } + m = stdm; + m->SetName(S(material.name())); + library->Add(m); + if (slot < NUM_MATERIAL_SLOTS) { + max_interface->PutMtlToMtlEditor(m,slot++); + } + } + return m; +} + +Mtl* ComposeMultiMaterial(std::map, Mtl*>& multi_mats, MtlBaseLib* library, Interface* max_interface, int& slot, const std::vector& materials, const std::string& object_type, const std::vector& material_ids) { + std::vector material_names; + bool needs_default = std::find(material_ids.begin(), material_ids.end(), -1) != material_ids.end(); + if (needs_default) { + material_names.push_back(object_type); + } + for (auto it = materials.begin(); it != materials.end(); ++it) { + material_names.push_back(it->name()); + } + Mtl* default_material = 0; + if (needs_default) { + default_material = FindMaterialByName(library, object_type); + if (default_material == 0) { + default_material = NewDefaultStdMat(); + default_material->SetName(S(object_type)); + library->Add(default_material); + if (slot < NUM_MATERIAL_SLOTS) { + max_interface->PutMtlToMtlEditor(default_material, slot++); + } + } + } + if (material_names.size() == 1) { + if (needs_default) { + return default_material; + } else { + return FindOrCreateMaterial(library, max_interface, slot, *materials.begin()); + } + } + std::map, Mtl*>::const_iterator i = multi_mats.find(material_names); + if (i != multi_mats.end()) { + return i->second; + } + MultiMtl* multi_mat = NewDefaultMultiMtl(); + multi_mat->SetNumSubMtls(material_names.size()); + int mtl_id = 0; + if (needs_default) { + multi_mat->SetSubMtlAndName(mtl_id ++, default_material, default_material->GetName()); + } + for (auto it = materials.begin(); it != materials.end(); ++it) { + Mtl* mtl = FindOrCreateMaterial(library, max_interface, slot, *it); + multi_mat->SetSubMtl(mtl_id ++, mtl); + } + library->Add(multi_mat); + if (slot < NUM_MATERIAL_SLOTS) { + max_interface->PutMtlToMtlEditor(multi_mat,slot++); + } + multi_mats.insert(std::pair, Mtl*>(material_names, multi_mat)); + return multi_mat; +} + int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL suppressPrompts) { IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS,false); @@ -119,79 +216,59 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, itfc->ProgressStart(_T("Importing file..."), TRUE, fn, NULL); - //std::map dict; MtlBaseLib* mats = itfc->GetSceneMtls(); int slot = mats->Count(); + std::map, Mtl*> material_cache; + do{ - const IfcGeomObjects::IfcGeomObject* o = IfcGeomObjects::Get(); - -#if MAX_RELEASE > 14000 - TSTR o_type = TSTR::FromCStr(o->type.c_str()); - TSTR o_guid = TSTR::FromCStr(o->guid.c_str()); -#elif defined(_UNICODE) - TSTR o_type = WStr(o->type.c_str()); - TSTR o_guid = WStr(o->guid.c_str()); -#else - TSTR o_type = CStr(o->type.c_str()); - TSTR o_guid = CStr(o->guid.c_str()); -#endif + const IfcGeomObjects::IfcGeomObject* o = IfcGeomObjects::Get(); - Mtl *m; - const int matIndex = mats->FindMtlByName(o_type); - if ( matIndex == -1 ) { - StdMat2* stdm = GetMaterial(o->type); - m = stdm; - m->SetName(o_type); - mats->Add(m); - itfc->PutMtlToMtlEditor(m,slot++); - } else { - m = static_cast((*mats)[matIndex]); - } - - // This mapping is useless for now, because this even in case - // meshes entities in IFC share the same representation elements - // they will never be given the same id. - // TODO: Fix this! - // std::map::const_iterator it = dict.find(o->mesh->id); + TSTR o_type = S(o->type()); + TSTR o_guid = S(o->guid()); - TriObject* tri; - // if ( it == dict.end() ) { - tri = CreateNewTriObject(); - const int numVerts = o->mesh->verts.size()/3; - tri->mesh.setNumVerts(numVerts); - for( int i = 0; i < numVerts; i ++ ) { - tri->mesh.setVert(i,o->mesh->verts[3*i+0],o->mesh->verts[3*i+1],o->mesh->verts[3*i+2]); - } - const int numFaces = o->mesh->faces.size()/3; - tri->mesh.setNumFaces(numFaces); - for( int i = 0; i < numFaces; i ++ ) { - tri->mesh.faces[i].setVerts(o->mesh->faces[3*i+0],o->mesh->faces[3*i+1],o->mesh->faces[3*i+2]); - tri->mesh.faces[i].setEdgeVisFlags(o->mesh->edges[3*i+0],o->mesh->edges[3*i+1],o->mesh->edges[3*i+2]); - } + Mtl *m = ComposeMultiMaterial(material_cache, mats, itfc, slot, o->mesh().materials(), o->type(), o->mesh().material_ids()); + + TriObject* tri = CreateNewTriObject(); + + const int numVerts = o->mesh().verts().size()/3; + tri->mesh.setNumVerts(numVerts); + for( int i = 0; i < numVerts; i ++ ) { + tri->mesh.setVert(i,o->mesh().verts()[3*i+0],o->mesh().verts()[3*i+1],o->mesh().verts()[3*i+2]); + } + const int numFaces = o->mesh().faces().size()/3; + tri->mesh.setNumFaces(numFaces); + + bool needs_default = std::find(o->mesh().material_ids().begin(), o->mesh().material_ids().end(), -1) != o->mesh().material_ids().end(); + + for( int i = 0; i < numFaces; i ++ ) { + tri->mesh.faces[i].setVerts(o->mesh().faces()[3*i+0],o->mesh().faces()[3*i+1],o->mesh().faces()[3*i+2]); + tri->mesh.faces[i].setEdgeVisFlags(o->mesh().edges()[3*i+0],o->mesh().edges()[3*i+1],o->mesh().edges()[3*i+2]); + MtlID mtlid = o->mesh().material_ids()[i]; + if (needs_default) mtlid ++; + tri->mesh.faces[i].setMatID(mtlid); + } - tri->mesh.buildNormals(); - // Either use this or undefine the FACESETS_AS_COMPOUND option in IfcGeom.h to have - // properly oriented normals. Using only the line below will result in a consistent - // orientation of normals accross shells, but not always oriented towards the - // outside. - // tri->mesh.UnifyNormals(false); - tri->mesh.BuildStripsAndEdges(); - tri->mesh.InvalidateTopologyCache(); - tri->mesh.InvalidateGeomCache(); - - // dict[o->mesh->id] = tri; - // } else { - // tri = (*it).second; - // } + tri->mesh.buildNormals(); + // Either use this or undefine the FACESETS_AS_COMPOUND option in IfcGeom.h to have + // properly oriented normals. Using only the line below will result in a consistent + // orientation of normals accross shells, but not always oriented towards the + // outside. + // tri->mesh.UnifyNormals(false); + tri->mesh.BuildStripsAndEdges(); + tri->mesh.InvalidateTopologyCache(); + tri->mesh.InvalidateGeomCache(); ImpNode* node = impitfc->CreateNode(); node->Reference(tri); node->SetName(o_guid); - node->GetINode()->SetMtl(m); - node->SetTransform(0,Matrix3 ( Point3(o->matrix[0],o->matrix[1],o->matrix[2]),Point3(o->matrix[3],o->matrix[4],o->matrix[5]), - Point3(o->matrix[6],o->matrix[7],o->matrix[8]),Point3(o->matrix[9],o->matrix[10],o->matrix[11]) )); + node->GetINode()->Hide(o->type() == "IfcOpeningElement" || o->type() == "IfcSpace"); + if (m) { + node->GetINode()->SetMtl(m); + } + node->SetTransform(0,Matrix3 ( Point3(o->matrix()[0],o->matrix()[1],o->matrix()[2]),Point3(o->matrix()[3],o->matrix()[4],o->matrix()[5]), + Point3(o->matrix()[6],o->matrix()[7],o->matrix()[8]),Point3(o->matrix()[9],o->matrix()[10],o->matrix()[11]) )); impitfc->AddNodeToScene(node); itfc->ProgressUpdate(IfcGeomObjects::Progress(),true,_T("")); diff --git a/src/ifcmax/MaxMaterials.h b/src/ifcmax/MaxMaterials.h deleted file mode 100644 index 101b77a086..0000000000 --- a/src/ifcmax/MaxMaterials.h +++ /dev/null @@ -1,48 +0,0 @@ -/******************************************************************************** - * * - * This file is part of IfcOpenShell. * - * * - * IfcOpenShell is free software: you can redistribute it and/or modify * - * it under the terms of the Lesser GNU General Public License as published by * - * the Free Software Foundation, either version 3.0 of the License, or * - * (at your option) any later version. * - * * - * IfcOpenShell 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 * - * Lesser GNU General Public License for more details. * - * * - * You should have received a copy of the Lesser GNU General Public License * - * along with this program. If not, see . * - * * - ********************************************************************************/ - -/******************************************************************************** - * * - * This file defines materials for use in 3ds Max for several IFC datatypes * - * * - ********************************************************************************/ - -#include - -#include "Max.h" -#include "stdmat.h" - -StdMat2* GetMaterial(const std::string& s) { - StdMat2* mat = NewDefaultStdMat(); - TimeValue t (-1); - mat->SetSpecular(Color(0.2f,0.2f,0.2f),t); - mat->SetAmbient(Color(0.1f,0.1f,0.1f),t); - mat->SetWire( s == "IfcSpace" || s == "IfcOpeningElement" ); - if ( s == "IfcSite" ) { mat->SetDiffuse(Color(0.75f,0.8f,0.65f),t); } - if ( s == "IfcSlab" ) { mat->SetDiffuse(Color(0.4f,0.4f,0.4f),t); } - if ( s == "IfcWallStandardCase" ) { mat->SetDiffuse(Color(0.9f,0.9f,0.9f),t); } - if ( s == "IfcWall" ) { mat->SetDiffuse(Color(0.9f,0.9f,0.9f),t); } - if ( s == "IfcWindow" ) { mat->SetDiffuse(Color(0.75f,0.8f,0.75f),t); mat->SetSpecular(Color(1.0f,1.0f,1.0f),t); - mat->SetAmbient(Color(0.0f,0.0f,0.0f),t); mat->SetShininess(500.0f,t); mat->SetOpacity(0.3f,t); } - if ( s == "IfcDoor" ) { mat->SetDiffuse(Color(0.55f,0.3f,0.15f),t); } - if ( s == "IfcBeam" ) { mat->SetDiffuse(Color(0.75f,0.7f,0.7f),t); } - if ( s == "IfcRailing" ) { mat->SetDiffuse(Color(0.75f,0.7f,0.7f),t); } - if ( s == "IfcMember" ) { mat->SetDiffuse(Color(0.75f,0.7f,0.7f),t); } - return mat; -} \ No newline at end of file