From a9af9341b9b1f7f693505c7227bcd638edcf39a8 Mon Sep 17 00:00:00 2001 From: Josef Wienerroither Date: Mon, 8 Dec 2025 14:43:46 +0100 Subject: [PATCH 1/5] chore: update ifcmax cmakelists --- src/ifcmax/CMakeLists.txt | 107 +++++++++++++++++++++++++++++++------- src/ifcmax/IfcMax.rc | Bin 0 -> 4088 bytes src/ifcmax/resource.h | 23 ++++++++ 3 files changed, 111 insertions(+), 19 deletions(-) create mode 100644 src/ifcmax/IfcMax.rc create mode 100644 src/ifcmax/resource.h diff --git a/src/ifcmax/CMakeLists.txt b/src/ifcmax/CMakeLists.txt index d306758b67..2d451e7eab 100644 --- a/src/ifcmax/CMakeLists.txt +++ b/src/ifcmax/CMakeLists.txt @@ -18,9 +18,20 @@ ################################################################################ # check for 3ds Max SDK -foreach(max_year RANGE 2014 2030) - set(max_sdk "$ENV{ADSK_3DSMAX_SDK_${max_year}}") +set(valid_max_years 2027 2026 2025 2024 2023 2022 2021 2020 2019 2018 2017) +# might be dangerous to use tools 143 for all max versions +set(max_toolset_versions_143 "2017" "2018" "2019" "2020" "2021" "2022" "2023" "2024" "2025" "2026" "2027" ) +# set(max_toolset_versions_143 "2025" "2026" "2027" ) +# set(max_toolset_versions_142 "2022" "2023" "2024" ) +# set(max_toolset_versions_141 "2020" "2021" ) +# set(max_toolset_versions_140 "2017" "2018" "2019" ) +# set(max_toolset_versions_110 "2015" "2016" ) +# set(max_toolset_versions_100 "2013" "2014" ) +# set(max_toolset_versions_90 "2010" "2011" "2012" ) + +foreach(max_year ${valid_max_years}) + set(max_sdk "$ENV{ADSK_3DSMAX_SDK_${max_year}}") if(NOT "${max_sdk}" STREQUAL "") message(STATUS "Autodesk 3ds Max SDK ${max_year} found at ${max_sdk}") list(APPEND FOUND_MAX_YEARS ${max_year}) @@ -29,22 +40,41 @@ foreach(max_year RANGE 2014 2030) endif() endforeach() +message(STATUS) + if(HAS_MAX) - # build libraray for each found 3ds Max SDK + # set depenency include and link directoris outside of MaxSDK loop + include_directories(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ) + link_directories(${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR} ${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS} ) + + # Specify individual source files + set(MAX_SOURCES + IfcMax.h + IfcMax.cpp + IfcMax.rc + resource.h + # IfcHelper.h + # IfcHelper.cpp + # MaxUtils.h + # MaxUtils.cpp + ) + + # build library for each found 3ds Max SDK foreach(max_year max_sdk IN ZIP_LISTS FOUND_MAX_YEARS FOUND_MAX_SDKS) - message(STATUS "Building IFCMax library for Autodesk 3ds Max SDK ${max_year}") + # skip 3ds Max versions that do not match the vs toolset + if( NOT ${max_year} IN_LIST max_toolset_versions_${MSVC_TOOLSET_VERSION} ) + continue() + endif() - include_directories(${INCLUDE_DIRECTORIES} ${OPENCOLLADA_INCLUDE_DIRS} ${ICU_INCLUDE_DIR} - ${Boost_INCLUDE_DIRS} ${max_sdk}/include - ) + message(STATUS "Adding build target: IFCMax for 3ds Max SDK ${max_year}, Tier: ${BUILD_TIER_NAME}") - # All recent versions of 3ds Max (2014 and newer) are 64-bit only so assume lib/x64 directory - link_directories(${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OPENCOLLADA_LIBRARY_DIR} - ${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS} ${max_sdk}/lib/x64/Release - ) - - add_library(IfcMax_${max_year} SHARED IfcMax.h IfcMax.cpp) + add_library(IfcMax_${max_year} SHARED ${MAX_SOURCES}) + + target_include_directories(IfcMax_${max_year} PRIVATE ${max_sdk}/include) + + # All recent versions of 3ds Max (2014 and newer) are 64-bit only so assume lib/x64 directory + target_link_directories(IfcMax_${max_year} PRIVATE ${max_sdk}/lib/x64/Release) # TODO: find the minimal subset of 3dsmax libraries to reference target_link_libraries(IfcMax_${max_year} ${IFCOPENSHELL_LIBRARIES} @@ -63,8 +93,6 @@ if(HAS_MAX) maxnet.lib Maxscrpt.lib maxutil.lib - MenuMan.lib - menus.lib mesh.lib MNMath.lib Paramblk2.lib @@ -73,14 +101,55 @@ if(HAS_MAX) RenderUtil.lib tessint.lib viewfile.lib - zlibdll.lib - ${OpenCASCADE_LIBRARIES} - ) + ${OPENCASCADE_LIBRARIES} + ) + + # Note: libraries build by same major vs toolset versions are binary compatible. so v14x builds can be intermixed + # Older Max versions using v110 or older require dependencies being build using the according toolset version ( most likely ) + if( ${max_year} IN_LIST max_toolset_versions_143 ) + set_target_properties( IfcMax_${max_year} PROPERTIES VS_PLATFORM_TOOLSET v143) + elseif( ${max_year} IN_LIST max_toolset_versions_142 ) + set_target_properties( IfcMax_${max_year} PROPERTIES VS_PLATFORM_TOOLSET v142) + elseif( ${max_year} IN_LIST max_toolset_versions_141 ) + set_target_properties( IfcMax_${max_year} PROPERTIES VS_PLATFORM_TOOLSET v141) + elseif( ${max_year} IN_LIST max_toolset_versions_140 ) + set_target_properties( IfcMax_${max_year} PROPERTIES VS_PLATFORM_TOOLSET v140) + elseif( ${max_year} IN_LIST max_toolset_versions_110 ) + set_target_properties( IfcMax_${max_year} PROPERTIES VS_PLATFORM_TOOLSET v110) + elseif( ${max_year} IN_LIST max_toolset_versions_100 ) + set_target_properties( IfcMax_${max_year} PROPERTIES VS_PLATFORM_TOOLSET v100) + elseif( ${max_year} IN_LIST max_toolset_versions_90 ) + set_target_properties( IfcMax_${max_year} PROPERTIES VS_PLATFORM_TOOLSET v90) + endif() + # prevent minmax macro clashes occuring with ifcOpenShell v0.8 + target_compile_definitions(IfcMax_${max_year} PRIVATE NOMINMAX) + + # fix 3ds Max 2020 SDK's "/permissive-" flag incompatibility / disables C++ language conformance mode + if( ${max_year} EQUAL 2020 ) + set_source_files_properties( "IfcMax.cpp" PROPERTIES COMPILE_FLAGS "/permissive") + endif() + + # C++17 required for 3ds Max SDK 2025 and higher + if( ${max_year} GREATER_EQUAL 2025 ) + set_target_properties(IfcMax_${max_year} PROPERTIES CXX_STANDARD 17) + endif() + set_target_properties(IfcMax_${max_year} PROPERTIES SUFFIX ".dli") + + if(BUILD_TIER_NAME) + target_compile_definitions(IfcMax_${max_year} PRIVATE BUILD_${BUILD_TIER_NAME}_TIER) + + string(TOLOWER "${BUILD_TIER_NAME}" BUILD_TIER_lower) + if(BUILD_TIER_lower STREQUAL "free") + set_target_properties(IfcMax_${max_year} PROPERTIES OUTPUT_NAME "IfcMax_Free_${max_year}") + endif() + endif() + + install(TARGETS IfcMax_${max_year} RUNTIME DESTINATION ${BINDIR}) - install(TARGETS IfcMax_${max_year}) endforeach() + message(STATUS) else() message(STATUS "Autodesk 3ds Max SDK not found, is required to build IFCMax.") endif() diff --git a/src/ifcmax/IfcMax.rc b/src/ifcmax/IfcMax.rc new file mode 100644 index 0000000000000000000000000000000000000000..b6ed3491783ad0a8d6310a9b35b6dae49f29bfaa GIT binary patch literal 4088 zcmdUyT~8B16o${WiT`0OHxLB`qqnAAO0AUAumv?CX^^&9Qw!;~F(&?Y^?7GI&~|qb ziWh4p+nGH(Gw16)AN~Dn+qNyRLmSwIjqS=}p1w_>okELkYUeiOEwty1z%H$4Bc3tz z33C_Pm|5qhtS(pwyy>=qU9)G)p4t<*Y`b|4>WHsHc6Z(0QtJGceX)|;t&?kRU*Db6 z-DPW8WNkaKJ*(T1b?n%xQ1@6jtzn;_MEo9F1xkap=PwzGH@tLy4y=Y}y` z{U=yQc4(vZM}F&Q9ipe~QH8$Cv+R+-`{28?Z*p$Y{>8JHmncEU6k7>Nee_-p8{YE% z-eS#Ox&ZHvh`%A8iorl&>-c=cn~%eYRT7o4ZDgPzo{Oo0v)8kQ*y?g)+4ezI5>pZJ zb3$~5aPEMv21ED$WCXb<+uU&shC7^Ua(=^cZ9r{8Jz=gnoO(*Kug2YVV)dQ9;O>Zh z6)4G>by6KZcDSmsD!Z7i-hsF} zc#6mjiuDTXDsQ2?p~ZPs^X83(W#kIICgn( z3}xNk^B&J?!Uy#5^;9)f`BD{hOlDd{+I^(!z*YT*D(!00ZE|uS?mdROEJ+e0)fM_Z zUUp^BBP49QjGb>^$)4D6AKvn9o-O1PW%IkerTbKer|2T={BT;TClpmx$!i$G?VMfm zPn^TGOongIH0i*}5~)IYC-TUE-iOVQkJ;Z=mHxLbmL6ByHUw zA#{~gb-aNNdYg~8TP&nwsfA9mnmYN1b6U1m30wB?fFf83QC>+R_qMO~xE##I_1hWm z#fp@lm;X(tG@m1jwf6bf&#JL~7ioEYaJnuPOQU&dd>!)hWB(DUPq_OZk+ Date: Mon, 8 Dec 2025 14:44:50 +0100 Subject: [PATCH 2/5] chore: add opencascade 7.9.1 patch file --- win/patches/V7_9_1.patch | 86 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 win/patches/V7_9_1.patch diff --git a/win/patches/V7_9_1.patch b/win/patches/V7_9_1.patch new file mode 100644 index 0000000000..f36532e74e --- /dev/null +++ b/win/patches/V7_9_1.patch @@ -0,0 +1,86 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 34300d41ad..efe3065499 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -363,6 +363,10 @@ else() + set (USE_D3D OFF) + endif() + ++# IfcOpenShell begin ++add_definitions(-DHAVE_NO_DLL) ++# IfcOpenShell end ++ + # Enable/Disable the floating point exceptions (FPE) during runtime. + if (NOT BUILD_ENABLE_FPE_SIGNAL_HANDLER) + set (BUILD_ENABLE_FPE_SIGNAL_HANDLER OFF CACHE BOOL "${BUILD_ENABLE_FPE_SIGNAL_HANDLER_DESCR}" FORCE) +@@ -721,6 +725,8 @@ else() + OCCT_CHECK_AND_UNSET ("3RDPARTY_DOT_EXECUTABLE") + endif() + ++list (REMOVE_ITEM BUILD_TOOLKITS ExpToCasExe) ++ + # bison + if (BUILD_YACCLEX) + list (APPEND OCCT_3RDPARTY_CMAKE_LIST "adm/cmake/bison") +diff --git a/adm/cmake/occt_defs_flags.cmake b/adm/cmake/occt_defs_flags.cmake +index 5bd3313d3c..d647ff05ab 100644 +--- a/adm/cmake/occt_defs_flags.cmake ++++ b/adm/cmake/occt_defs_flags.cmake +@@ -214,7 +214,23 @@ if (CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) + set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s") + endif() + +-if (BUILD_RELEASE_DISABLE_EXCEPTIONS) +- set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNo_Exception") +- set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNo_Exception") +-endif() ++# IfcOpenShell begin ++# https://salsa.debian.org/science-team/opencascade/blob/739e7e9c4fbe575165eb3ff0251774bfad27139e/debian/patches/enable-exception-handling.patch ++# if (BUILD_RELEASE_DISABLE_EXCEPTIONS) ++# set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNo_Exception") ++# set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNo_Exception") ++# endif() ++ ++if (MSVC AND MSVC_STATIC_RUNTIME) ++ foreach(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL ++ CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE ++ CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO) ++ if (${flag} MATCHES "/MD") ++ string(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}") ++ endif() ++ if (${flag} MATCHES "/MDd") ++ string(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}") ++ endif() ++ endforeach() ++endif() ++# IfcOpenShell end +diff --git a/adm/cmake/occt_toolkit.cmake b/adm/cmake/occt_toolkit.cmake +index 22e94d0629..c6995bb247 100644 +--- a/adm/cmake/occt_toolkit.cmake ++++ b/adm/cmake/occt_toolkit.cmake +@@ -135,15 +135,22 @@ else() + else() + set (aReleasePdbConf) + endif() ++ # IfcOpenShell begin + if (BUILD_SHARED_LIBS) + install (FILES ${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/bin\${OCCT_INSTALL_BIN_LETTER}/${PROJECT_NAME}.pdb + CONFIGURATIONS Debug ${aReleasePdbConf} RelWithDebInfo + DESTINATION "${INSTALL_DIR_BIN}\${OCCT_INSTALL_BIN_LETTER}") + else() +- install (FILES ${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/lib\${OCCT_INSTALL_BIN_LETTER}/${PROJECT_NAME}.pdb +- CONFIGURATIONS Debug ${aReleasePdbConf} RelWithDebInfo +- DESTINATION "${INSTALL_DIR_LIB}\${OCCT_INSTALL_BIN_LETTER}") ++ set_target_properties (${PROJECT_NAME} PROPERTIES ++ COMPILE_PDB_NAME ${PROJECT_NAME} ++ COMPILE_PDB_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/pdb/ ++ ) ++ ++ install (FILES ${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/pdb/\${CMAKE_INSTALL_CONFIG_NAME}/${PROJECT_NAME}.pdb ++ CONFIGURATIONS Debug ${aReleasePdbConf} RelWithDebInfo ++ DESTINATION "${INSTALL_DIR_LIB}\${OCCT_INSTALL_BIN_LETTER}") + endif() ++ # IfcOpenShell end + endif() + + if (BUILD_SHARED_LIBS AND NOT "${BUILD_SHARED_LIBRARY_NAME_POSTFIX}" STREQUAL "") From 11daabc3ea80d6acdfe07c84718e9886bb86054b Mon Sep 17 00:00:00 2001 From: Josef Wienerroither Date: Mon, 8 Dec 2025 14:45:23 +0100 Subject: [PATCH 3/5] feature: add ifcmax free core --- src/ifcmax/IfcMax.cpp | 554 +++++++++++++++++++++++++++++++----------- src/ifcmax/IfcMax.h | 34 +-- 2 files changed, 431 insertions(+), 157 deletions(-) diff --git a/src/ifcmax/IfcMax.cpp b/src/ifcmax/IfcMax.cpp index 6252e97353..638c44cfd3 100644 --- a/src/ifcmax/IfcMax.cpp +++ b/src/ifcmax/IfcMax.cpp @@ -22,17 +22,44 @@ #include #include +#include +#include +#include +// should fix a iterator missallignment assertion ? +#define IFOPSH_WITH_ROCKSDB + +#include "../ifcgeom/Iterator.h" +#include "../ifcgeom/taxonomy.h" +#include "../ifcgeom/ConversionSettings.h" +#include "../ifcgeom/hybrid_kernel.h" + +#include "resource.h" #include "IfcMax.h" -#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" -#include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h" -#include "../ifcgeom/IfcGeomElement.h" +// include those at last, as they cause compile errors regarding boost templates +#include +#include + + +static const Class_ID IFCIMP_CLASS_ID = Class_ID(0x3f230dbf, 0x5b3015c2); +static const TSTR IFCIMP_CLASS_NAME = _T("IFCImp"); +static const TSTR IFCIMP_CATEGORY_NAME = _T("Importer Plugins"); static const int NUM_MATERIAL_SLOTS = 24; -BOOL WINAPI DllMain(HINSTANCE /*hinstDLL*/, ULONG /*fdwReason*/, LPVOID /*lpvReserved*/) { +static HINSTANCE hInstance; +static TCHAR *GetString(int id) +{ + static TCHAR buf[256]; + if (hInstance) + return LoadString(hInstance, id, buf, _countof(buf)) ? buf : NULL; + return NULL; +} + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, ULONG /*fdwReason*/, LPVOID /*lpvReserved*/) { static int controlsInit = false; + hInstance = hinstDLL; if (!controlsInit) { controlsInit = true; InitCommonControls(); @@ -45,65 +72,51 @@ public: int IsPublic() { return 1; } void * Create(BOOL /*loading = FALSE*/) { return new IFCImp; } // TODO Delete() function? - const TCHAR * ClassName() { return _T("IFCImp"); } + const TCHAR* ClassName() { return IFCIMP_CLASS_NAME; } + +#if MAX_VERSION_MAJOR >= 24 + const TCHAR * NonLocalizedClassName() { return ClassName(); } +#endif + SClass_ID SuperClassID() { return SCENE_IMPORT_CLASS_ID; } - Class_ID ClassID() { return Class_ID(0x3f230dbf, 0x5b3015c2); } - const TCHAR* Category() { return _T("Chrutilities"); } + Class_ID ClassID() { return IFCIMP_CLASS_ID; } + const TCHAR* Category() { return IFCIMP_CATEGORY_NAME; } } IFCImpDesc; #define DLLEXPORT __declspec(dllexport) extern "C" { - -DLLEXPORT const TCHAR* LibDescription() { - return _T("IfcOpenShell IFC Importer"); -} +#if BUILD_FREE_TIER +DLLEXPORT const TCHAR* LibDescription() { return GetString(IDS_LIBDESCRIPTION_FREE); } +#else + DLLEXPORT const TCHAR* LibDescription() { return GetString(IDS_LIBDESCRIPTION); } +#endif DLLEXPORT int LibNumberClasses() { return 1; } -DLLEXPORT ClassDesc* LibClassDesc(int i) { - return i == 0 ? &IFCImpDesc : 0; -} +DLLEXPORT ClassDesc* LibClassDesc(int i) { return i == 0 ? &IFCImpDesc : 0; } -DLLEXPORT ULONG LibVersion() { - return VERSION_3DSMAX; -} +DLLEXPORT ULONG LibVersion() { return VERSION_3DSMAX; } } // extern "C" int IFCImp::ExtCount() { return 1; } -const TCHAR * IFCImp::Ext(int n) { - return n == 0 ? _T("IFC") : _T(""); -} +const TCHAR * IFCImp::Ext(int n) { return n == 0 ? _T("IFC") : _T(""); } -const TCHAR * IFCImp::LongDesc() { - return _T("IfcOpenShell IFC Importer for 3ds Max"); -} +const TCHAR * IFCImp::LongDesc() { return GetString(IDS_LONG_DESCRIPTION); } -const TCHAR * IFCImp::ShortDesc() { - return _T("Industry Foundation Classes"); -} +const TCHAR * IFCImp::ShortDesc() { return GetString(IDS_SHORT_DESCRIPTION); } -const TCHAR * IFCImp::AuthorName() { - return _T("Thomas Krijnen"); -} +const TCHAR * IFCImp::AuthorName() { return GetString(IDS_AUTHOR_NAME); } -const TCHAR * IFCImp::CopyrightMessage() { - return _T("Copyright (c) 2011-2016 IfcOpenShell"); -} +const TCHAR * IFCImp::CopyrightMessage() { return GetString(IDS_COPYRIGHT_MESSAGE); } -const TCHAR * IFCImp::OtherMessage1() { - return _T(""); -} +const TCHAR * IFCImp::OtherMessage1() { return _T(""); } -const TCHAR * IFCImp::OtherMessage2() { - return _T(""); -} +const TCHAR * IFCImp::OtherMessage2() { return _T(""); } -unsigned int IFCImp::Version() { - return 12; -} +unsigned int IFCImp::Version() { return 25; } // TODO Use this in IFCImp::ShowAbout() if/when wanted //static BOOL CALLBACK AboutBoxDlgProc(HWND /*hWnd*/, UINT /*msg*/, WPARAM /*wParam*/, LPARAM /*lParam*/) { @@ -122,6 +135,40 @@ DWORD WINAPI fn(LPVOID /*arg*/) { return 0; } # define S(x) (CStr(x.c_str())) #endif + +// Function to log messages to the Listener +static void LogToListener(const MCHAR* format, ...) +{ + if (format == nullptr) { + return; + } + + const int BUFFER_SIZE = 2048; + static MCHAR buffer[BUFFER_SIZE]; + + va_list args; + + va_start(args, format); + int result = _vstprintf_s(buffer, BUFFER_SIZE, format, args); + + va_end(args); + +#if BUILD_FREE_TIER + if(result < 0) { + the_listener->edit_stream->printf(_M("IfcImp (Free): Skipped invalid log output !\n")); + return; + } + the_listener->edit_stream->printf(_M("IfcImp (Free): %s"), buffer); +#else + if(result < 0) { + the_listener->edit_stream->printf(_M("IfcImp: Skipped invalid log output !\n")); + return; + } + the_listener->edit_stream->printf(_M("IfcImp: %s"), buffer); +#endif +} + + static Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) { TSTR mat_name = S(material_name); const int mat_index = library->FindMtlByName(mat_name); @@ -132,27 +179,32 @@ static Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_ return m; } -static Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const IfcGeom::Material& material) { - Mtl* m = FindMaterialByName(library, material.name()); + +static Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const ifcopenshell::geometry::taxonomy::style::ptr styleptr) { + + auto& style = *styleptr; + std::string material_name = style.name; + + 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 (style.diffuse) { + const ifcopenshell::geometry::taxonomy::colour diffuse = style.diffuse; + stdm->SetDiffuse(Color(diffuse.r(), diffuse.g(), diffuse.b()),t); } - if (material.hasSpecular()) { - const double* specular = material.specular(); - stdm->SetSpecular(Color(specular[0], specular[1], specular[2]),t); + if (style.specular) { + const ifcopenshell::geometry::taxonomy::colour specular = style.specular; + stdm->SetSpecular(Color(specular.r(), specular.g(), specular.b()),t); } - if (material.hasSpecularity()) { - stdm->SetShininess((float)material.specularity(), t); + if (style.has_specularity()) { + stdm->SetShininess((float)style.specularity, t); } - if (material.hasTransparency()) { - stdm->SetOpacity(1.0f - (float)material.transparency(), t); + if (style.has_transparency()) { + stdm->SetOpacity(1.0f - (float)style.transparency, t); } m = stdm; - m->SetName(S(material.name())); + m->SetName(S(material_name)); library->Add(m); if (slot < NUM_MATERIAL_SLOTS) { max_interface->PutMtlToMtlEditor(m,slot++); @@ -161,18 +213,22 @@ static Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, return m; } + static Mtl* ComposeMultiMaterial(std::map, Mtl*>& multi_mats, MtlBaseLib* library, - Interface* max_interface, int& slot, const std::vector& materials, + Interface* max_interface, int& slot, const std::vector styleptrs, 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()); + + for (auto it = styleptrs.begin(); it != styleptrs.end(); ++it) { + material_names.push_back( (*it)->name); } + Mtl* default_material = 0; if (needs_default) { default_material = FindMaterialByName(library, object_type); @@ -185,13 +241,15 @@ static Mtl* ComposeMultiMaterial(std::map, Mtl*>& multi } } } + if (material_names.size() == 1) { if (needs_default) { return default_material; } else { - return FindOrCreateMaterial(library, max_interface, slot, *materials.begin()); + return FindOrCreateMaterial(library, max_interface, slot, *styleptrs.begin()); } } + std::map, Mtl*>::const_iterator i = multi_mats.find(material_names); if (i != multi_mats.end()) { return i->second; @@ -202,7 +260,7 @@ static Mtl* ComposeMultiMaterial(std::map, Mtl*>& multi if (needs_default) { multi_mat->SetSubMtlAndName(mtl_id ++, default_material, default_material->GetName()); } - for (auto it = materials.begin(); it != materials.end(); ++it) { + for (auto it = styleptrs.begin(); it != styleptrs.end(); ++it) { Mtl* mtl = FindOrCreateMaterial(library, max_interface, slot, *it); multi_mat->SetSubMtl(mtl_id ++, mtl); } @@ -214,114 +272,326 @@ static Mtl* ComposeMultiMaterial(std::map, Mtl*>& multi return multi_mat; } -int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL /*suppressPrompts*/) { +int IFCImp::DoImport(const TCHAR *file_name, ImpInterface *impitfc, Interface *ip, BOOL noPrompts ) { - IfcGeom::IteratorSettings settings; - settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false); - settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, true); - settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true); + ifcopenshell::geometry::Settings settings; + + //settings.get().value = 0.001; + //settings.get().value = 0.5; + + + // should adapt to 3ds Max Systemm units ? + //settings.get().value = 1.0; + //settings.get().value = 1.0; + //settings.get().value = 0.00001; + + //settings.get().value = 1.0; + //settings.get().value = true; + + //settings.get().value = false; + //settings.get().value = false; + //settings.get().value = false; + //settings.get().value = false; + + + settings.get().value = true; // should be true + settings.get().value = true; // should be true + settings.get().value = false; // should be false to get a pivot with correct coordinates + //settings.get().value = false; + //settings.get().value = false; + + + // some settings which seem to make sense + settings.get().value = true; + settings.get().value = true; // should be true + + // ATTENTION: breaks hierarchy positioning when active ( "site-local-placement" ) + settings.get().value = false; // should be FALSE + + // when vertex welding is enabled, normals calculation is internally disabled ( see OpenCascadeConversionResult.cpp:239 ) + settings.get().value = true; // should be true + + settings.get().value = false; + settings.get().value = false; + + + settings.get().value = 32; // should be 32 + settings.get().value = true; + settings.get().value = ifcopenshell::geometry::settings::SURFACES_AND_SOLIDS; // default is SURFACES_AND_SOLIDS #ifdef _UNICODE - int fn_buffer_size = WideCharToMultiByte(CP_UTF8, 0, name, -1, 0, 0, 0, 0); + int fn_buffer_size = WideCharToMultiByte(CP_UTF8, 0, file_name, -1, 0, 0, 0, 0); char* fn_mb = new char[fn_buffer_size]; - WideCharToMultiByte(CP_UTF8, 0, name, -1, fn_mb, fn_buffer_size, 0, 0); + WideCharToMultiByte(CP_UTF8, 0, file_name, -1, fn_mb, fn_buffer_size, 0, 0); #else const char* fn_mb = name; #endif - IfcParse::IfcFile file(fn_mb); - IfcGeom::Iterator iterator(settings, &file); - delete fn_mb; - if (!iterator.initialize()) return false; + IfcParse::IfcFile file(fn_mb); - itfc->ProgressStart(_T("Importing file..."), TRUE, fn, NULL); + IfcParse::file_open_status status = file.good(); - MtlBaseLib* mats = itfc->GetSceneMtls(); + if (status != IfcParse::file_open_status::SUCCESS) { + const MCHAR* reason = status == IfcParse::file_open_status::UNSUPPORTED_SCHEMA + ? _M("Import aborted: unsupported IFC Schema") + : _M("Import aborted: failure parsing IFC file"); + + ip->DisplayTempPrompt( reason, 10000 ); + return false; + } + + auto mapped = file.instances_by_type( "IfcMappedItem" ); + auto annotations = file.instances_by_type("IfcAnnotation"); + auto solids = file.instances_by_type("IfcSolidModel"); + + // cgal kernels produce std::vector incompatiblities + //auto kernel = ifcopenshell::geometry::kernels::construct(&file, "hybrid-cgal-simple-opencascade", settings); + + //auto kernel = ifcopenshell::geometry::kernels::construct(&file, "opencascade", settings); + //IfcGeom::Iterator iterator( std::move( kernel), settings, &file); + + IfcGeom::Iterator iterator( + ifcopenshell::geometry::kernels::construct(&file, "opencascade", settings), + settings, + &file); + + + delete[] fn_mb; + + LogToListener(_M("Importing '%s'...\n"), file_name); + if (!iterator.initialize()) { + if(!iterator.had_error_processing_elements()) { + LogToListener(_M("No elements found in '%s'...\n"), file_name); + return IMPEXP_SUCCESS; + } + + LogToListener(_M("Error processing elements in '%s'...\n"), file_name); + return IMPEXP_FAIL; + } + + ip->ProgressStart(_T("Importing file..."), TRUE, fn, NULL); + + MtlBaseLib* mats = ip->GetSceneMtls(); int slot = mats->Count(); + std::vector impnode_cache; std::map, Mtl*> material_cache; + + + bool wasCanceled=false; + auto startTime = std::chrono::high_resolution_clock::now(); + std::stringstream log_stream; do{ - const IfcGeom::TriangulationElement* o = static_cast*>(iterator.get()); - TSTR o_type = S(o->type()); - TSTR o_guid = S(o->guid()); + auto iter = iterator.get(); + auto prod = iter->product(); - Mtl *m = ComposeMultiMaterial(material_cache, mats, itfc, slot, o->geometry().materials(), o->type(), o->geometry().material_ids()); + const IfcGeom::Element* element = static_cast(iterator.get()); + const IfcGeom::BRepElement* brepElement = static_cast(iterator.get_native()); + const IfcGeom::TriangulationElement* triElement = static_cast(iterator.get()); - TriObject* tri = CreateNewTriObject(); + const TSTR e_type = TSTR::FromUTF8(element->type().c_str()); + const TSTR e_guid = TSTR::FromUTF8(element->guid().c_str()); + const TSTR e_name = TSTR::FromUTF8(element->name().c_str()); + const TSTR e_idStr = TSTR(std::to_wstring(element->id()).c_str()); - const int numVerts = (int)o->geometry().verts().size()/3; - tri->mesh.setNumVerts(numVerts); - for( int i = 0; i < numVerts; i ++ ) { - tri->mesh.setVert(i,o->geometry().verts()[3*i+0],o->geometry().verts()[3*i+1],o->geometry().verts()[3*i+2]); - } - const int numFaces = (int)o->geometry().faces().size()/3; - tri->mesh.setNumFaces(numFaces); - bool needs_default = std::find(o->geometry().material_ids().begin(), o->geometry().material_ids().end(), -1) != o->geometry().material_ids().end(); - - typedef std::pair edge_t; - - std::set face_boundaries; - for(std::vector::const_iterator it = o->geometry().edges().begin(); it != o->geometry().edges().end();) { - const int v1 = *it++; - const int v2 = *it++; - - const edge_t e((std::min)(v1, v2), (std::max)(v1, v2)); - face_boundaries.insert(e); - } - - for( int i = 0; i < numFaces; i ++ ) { - const int v1 = o->geometry().faces()[3*i+0]; - const int v2 = o->geometry().faces()[3*i+1]; - const int v3 = o->geometry().faces()[3*i+2]; - - const edge_t e1((std::min)(v1, v2), (std::max)(v1, v2)); - const edge_t e2((std::min)(v2, v3), (std::max)(v2, v3)); - const edge_t e3((std::min)(v3, v1), (std::max)(v3, v1)); - - const bool b1 = face_boundaries.find(e1) != face_boundaries.end(); - const bool b2 = face_boundaries.find(e2) != face_boundaries.end(); - const bool b3 = face_boundaries.find(e3) != face_boundaries.end(); - - tri->mesh.faces[i].setVerts(v1, v2, v3); - tri->mesh.faces[i].setEdgeVisFlags(b1, b2, b3); - - MtlID mtlid = (MtlID)o->geometry().material_ids()[i]; - if (needs_default) { - mtlid ++; + // dump out the parent tree up to IfcProject for each element + log_stream.str(""); + auto parents = element->parents(); // keep a persistent copy + if (!parents.empty()) { + for(auto it =parents.rbegin(); it != parents.rend(); ++it) { + auto p_e = *it; + log_stream << "->" << p_e->type() << " [#" << p_e->id() << "]"; } - 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 across 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()->Hide(o->type() == "IfcOpeningElement" || o->type() == "IfcSpace"); - if (m) { - node->GetINode()->SetMtl(m); - } - const std::vector& matrix_data = o->transformation().matrix().data(); - node->SetTransform(0,Matrix3 ( Point3(matrix_data[0],matrix_data[1],matrix_data[2]),Point3(matrix_data[3],matrix_data[4],matrix_data[5]), - Point3(matrix_data[6],matrix_data[7],matrix_data[8]),Point3(matrix_data[9],matrix_data[10],matrix_data[11]) )); - impitfc->AddNodeToScene(node); + LogToListener(_M("%3d%% - [#%d] %s: '%s' %s\n"), iterator.progress(), element->id(), e_type, e_name, TSTR::FromUTF8( log_stream.str().c_str() ) ); - itfc->ProgressUpdate(iterator.progress(), true, _T("")); + Mtl *mat = ComposeMultiMaterial(material_cache, mats, ip, slot, triElement->geometry().materials(), triElement->type(), triElement->geometry().material_ids()); + + ImpNode* impNode = impitfc->CreateNode(); + + RefResult refSuccess = REF_INVALID; + + auto mesh = BuildMesh(triElement); + + if ( mesh != nullptr) + refSuccess = impNode->Reference(mesh); + + if (refSuccess != REF_SUCCEED) { + LogToListener(_M("Error creating importer reference for imported element #%d.\n"), element->id()); + continue; + } + + TSTR longName; + BuildFullName( *prod, longName); + impNode->SetName(longName); + + const auto& mtx = triElement->transformation().data()->ccomponents(); + impNode->SetTransform(0, Matrix3(Point3(mtx(0, 0), mtx(1, 0), mtx(2, 0)), Point3(mtx(0, 1), mtx(1, 1), mtx(2, 1)), Point3(mtx(0, 2), mtx(1, 2), mtx(2, 2)), Point3(mtx(0, 3), mtx(1, 3), mtx(2, 3)))); + + INode* inode = impNode->GetINode(); + + inode->Hide(triElement->type() == "IfcOpeningElement" || triElement->type() == "IfcSpace"); + + if (mat != nullptr) { + inode->SetMtl(mat); + + // set wirecolor to material color + inode->SetWireColor(mat->GetDiffuse().toRGB()); + } + + // add to the cache, not to the scene, thisd allows a clean exit if cancel was pressed + impnode_cache.push_back(impNode); + + ip->ProgressUpdate(iterator.progress(), true, _T("")); + + if (ip->GetCancel()) { + wasCanceled = noPrompts ? true : VerifyCancel(); + if (wasCanceled) + break; + else + ip->SetCancel(false); + } } while (iterator.next()); - itfc->ProgressEnd(); - - return true; + ip->ProgressEnd(); + + if(wasCanceled) { + LogToListener(_T("Import canceled by User\n")); + return IMPEXP_CANCEL; + } + // add all objects to the scene + for( int i = 0; i < impnode_cache.size(); i++ ) + impitfc->AddNodeToScene(impnode_cache[i]); + + // Calculate the duration + unsigned int seconds = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startTime).count(); + LogToListener(_M("Import finished in %u seconds\n"), seconds); + + return IMPEXP_SUCCESS; +} + +BOOL IFCImp::VerifyCancel() { +#if MAX_VERSION_MAJOR < 23 + return IDYES == MaxMsgBox(GetCOREInterface()->GetMAXHWnd(), GetString(IDS_IMPORT_CANCEL_MESSAGE), GetString(IDS_IMPORT_CANCEL_CAPTION), MB_YESNO); +#else + // new MaxMessageBox API + return IDYES == MaxSDK::MaxMessageBox(GetCOREInterface()->GetMAXHWnd(), GetString(IDS_IMPORT_CANCEL_MESSAGE), GetString(IDS_IMPORT_CANCEL_CAPTION), MB_YESNO); +#endif +} + + +void IFCImp::BuildFullName( const IfcUtil::IfcBaseEntity& entity, MSTR& long_name) +{ + auto name = TSTR::FromUTF8(entity.get_value("Name", "").c_str()); + + if( name.length() > 0) { + long_name.printf(_M("%s/%s [#%d]"), TSTR::FromUTF8(entity.declaration().name().c_str()), name, entity.id_); + } + else { + long_name.printf(_M("%s [#%d]"), TSTR::FromUTF8(entity.declaration().name().c_str()), entity.id_); + } +} + +TriObject* IFCImp::BuildMesh(const IfcGeom::TriangulationElement* element) { + TriObject* tri = CreateNewTriObject(); + + const IfcGeom::Representation::Triangulation& ios_mesh = element->geometry(); + + const auto& verts = ios_mesh.verts(); + const int numVerts = (int)verts.size() / 3; + + //const auto& normals = ios_mesh.normals(); + // const int numNormals = (int)normals.size() / 3; + + // const auto& uvs = ios_mesh.uvs(); + // const int numUVs = (int)uvs.size() / 3; + + + tri->mesh.setNumVerts(numVerts); + for (int i = 0; i < numVerts; i++) { + tri->mesh.setVert(i, Point3ByIndex(verts, i)); + //if( i < numNormals ) { + // tri->mesh.setNormal(i, Point3ByIndex(normals, i)); + // } + } + + bool needs_default = std::find(ios_mesh.material_ids().begin(), ios_mesh.material_ids().end(), -1) != ios_mesh.material_ids().end(); + + typedef std::pair edge_t; + + std::set face_boundaries; + for (std::vector::const_iterator it = ios_mesh.edges().begin(); it != ios_mesh.edges().end();) { + const int v1 = *it++; + const int v2 = *it++; + + const edge_t e((std::min)(v1, v2), (std::max)(v1, v2)); + face_boundaries.insert(e); + } + + const auto& faces = ios_mesh.faces(); + + const int numFaces = (int)faces.size() / 3; + + tri->mesh.setNumFaces(numFaces); + + for (int i = 0; i < numFaces; i++) { + const int v1 = faces[3 * i + 0]; + const int v2 = faces[3 * i + 1]; + const int v3 = faces[3 * i + 2]; + + const edge_t e1((std::min)(v1, v2), (std::max)(v1, v2)); + const edge_t e2((std::min)(v2, v3), (std::max)(v2, v3)); + const edge_t e3((std::min)(v3, v1), (std::max)(v3, v1)); + + const bool b1 = face_boundaries.find(e1) != face_boundaries.end(); + const bool b2 = face_boundaries.find(e2) != face_boundaries.end(); + const bool b3 = face_boundaries.find(e3) != face_boundaries.end(); + + tri->mesh.faces[i].setVerts(v1, v2, v3); + tri->mesh.faces[i].setEdgeVisFlags(b1, b2, b3); + + MtlID mtlid = (MtlID)ios_mesh.material_ids()[i]; + if (needs_default) { + mtlid++; + } + tri->mesh.faces[i].setMatID(mtlid); + } + + bool valid = tri->CheckObjectIntegrity(); + + if (!valid) { + return nullptr; + } + + // apply simple box mapping +#if MAX_VERSION_MAJOR < 22 + // in 3ds Max 2017-2019 SDK, Matrix3::Identity was declared in matrix3.h, but did'nt actually exist in the lib .... + Matrix3 ident(TRUE); + tri->mesh.ApplyUVWMap(MAP_ACAD_BOX, 1, 1, 1, 0, 0, 0, 0, ident); +#else + tri->mesh.ApplyUVWMap(MAP_ACAD_BOX, 1, 1, 1, 0, 0, 0, 0, Matrix3::Identity); +#endif + + // this one tends to crash, so we skip it for the time being + // 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 across shells, but not always oriented towards the + // outside. + // tri->mesh.UnifyNormals(false); + + tri->mesh.BuildStripsAndEdges(); + tri->mesh.InvalidateTopologyCache(); + tri->mesh.InvalidateGeomCache(); + return tri; +} + +inline Point3 IFCImp::Point3ByIndex(const std::vector& verts, int index) { + return Point3(verts[3 * index + 0], verts[3 * index + 1], verts[3 * index + 2]); } diff --git a/src/ifcmax/IfcMax.h b/src/ifcmax/IfcMax.h index 19a89d9da0..732d5f363f 100644 --- a/src/ifcmax/IfcMax.h +++ b/src/ifcmax/IfcMax.h @@ -21,23 +21,27 @@ #define IFCMAX_H #include "Max.h" +#include "../ifcgeom/IfcGeomElement.h" -extern ClassDesc* GetIFCImpDesc(); +class IFCImp : public SceneImport { + public: + int ExtCount(); // = 1 + const TCHAR* Ext(int n); // = "IFC" + const TCHAR* LongDesc(); // = "IFC Importer for 3ds Max" + const TCHAR* ShortDesc(); // = "Industry Foundation Classes" + const TCHAR* AuthorName(); // = "Josef Wienerroither" + const TCHAR* CopyrightMessage(); // = "Copyright (c) 2025 Josef Wienerroither, 2011-2016 IfcOpenShell" + const TCHAR* OtherMessage1(); // = "" + const TCHAR* OtherMessage2(); // = "" + unsigned int Version(); // = 25 + void ShowAbout(HWND hWnd); + int DoImport(const TCHAR* name, ImpInterface* ei, Interface* i, BOOL suppressPrompts); + BOOL VerifyCancel(); -class IFCImp : public SceneImport -{ -public: - int ExtCount(); // = 1 - const TCHAR * Ext(int n); // = "IFC" - const TCHAR * LongDesc(); // = "IfcOpenShell IFC Importer for 3ds Max" - const TCHAR * ShortDesc(); // = "Industry Foundation Classes" - const TCHAR * AuthorName(); // = "Thomas Krijnen" - const TCHAR * CopyrightMessage(); // = "Copyright (c) 2011-2016 IfcOpenShell" - const TCHAR * OtherMessage1(); // = "" - const TCHAR * OtherMessage2(); // = "" - unsigned int Version(); // = 12 - void ShowAbout(HWND hWnd); - int DoImport(const TCHAR *name,ImpInterface *ei,Interface *i, BOOL suppressPrompts); + private: + inline Point3 Point3ByIndex(const std::vector& verts, int index); + void BuildFullName(const IfcUtil::IfcBaseEntity& entity, MSTR& long_name); + TriObject* BuildMesh(const IfcGeom::TriangulationElement* triElement); }; #endif From 3add345bb76536f5265faa050e3ae1d491215011 Mon Sep 17 00:00:00 2001 From: Josef Wienerroither Date: Mon, 8 Dec 2025 15:04:18 +0100 Subject: [PATCH 4/5] feat: add ifcmax specific build-deps.cmd --- win/build-deps-ifcmax.cmd | 969 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 969 insertions(+) create mode 100644 win/build-deps-ifcmax.cmd diff --git a/win/build-deps-ifcmax.cmd b/win/build-deps-ifcmax.cmd new file mode 100644 index 0000000000..e91abdccf0 --- /dev/null +++ b/win/build-deps-ifcmax.cmd @@ -0,0 +1,969 @@ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: :: +:: 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 batch file expects CMake generator as %1 and build configuration type as %2. If not provided, +:: a deduced generator will be used for %1 and BUILD_CFG_DEFAULT for %2 (both set in vs-cfg.cmd) +:: Optionally a build type (Build/Rebuild/Clean) can be passed as %3. +:: +:: Example usage (all arguments are optional): +:: build-deps.cmd vs2022-x64 RelWithDebInfo Build + +@if not defined ECHO_ON ( echo off ) +echo. + +for %%Q in ("%~dp0\.") DO set "batpath=%%~fQ" + +if NOT "%CD%" == "%batpath%" ( + GOTO :ErrorAndPrintUsage +) + + +set PROJECT_NAME=IfcOpenShell +call utils\cecho.cmd 0 15 "This script fetches and builds all %PROJECT_NAME% dependencies" +echo. + +:: Enable the delayed environment variable expansion needed in vs-cfg.cmd. +setlocal EnableDelayedExpansion + +:: Make sure vcvarsall.bat is called and dev env set is up. +IF "%VSINSTALLDIR%"=="" ( + call utils\cecho.cmd 0 12 "Visual Studio environment variables not set- cannot proceed." + GOTO :ErrorAndPrintUsage +) + +:: Check for cl.exe - at least the "Typical" Visual Studio 2015 installation does not include the C++ toolset by default, +:: http://blogs.msdn.com/b/vcblog/archive/2015/07/24/setup-changes-in-visual-studio-2015-affecting-c-developers.aspx +where cl.exe 2>&1>NUL +if not %ERRORLEVEL%==0 ( + call utils\cecho.cmd 0 12 "%~nx0: cl.exe not in PATH. Make sure to select the C++ toolset when installing Visual Studio- cannot proceed." + GOTO :ErrorAndPrintUsage +) + +:: Set up variables depending on the used Visual Studio version +call vs-cfg.cmd %1 +IF NOT %ERRORLEVEL%==0 GOTO :Error + +:: Set up the BuildDepsCache.txt filename +IF DEFINED VS_TOOLSET ( + set BUILD_DEPS_CACHE_PATH=BuildDepsCache-%VS_PLATFORM%-%VS_TOOLSET%.txt +) ELSE ( + set BUILD_DEPS_CACHE_PATH=BuildDepsCache-%VS_PLATFORM%.txt +) + +:: fix for Visual C++ hanging when compiling 32-bit release OCCT up to version 7.4.0 +:: see https://tracker.dev.opencascade.org/view.php?id=31628 +SET COMPILE_WITH_WPO=FALSE + +call build-type-cfg.cmd %2 +IF NOT %ERRORLEVEL%==0 GOTO :Error + +set BUILD_TYPE=%3 +IF "%BUILD_TYPE%"=="" set BUILD_TYPE=Build + +IF NOT "!BUILD_TYPE!"=="Build" IF NOT "!BUILD_TYPE!"=="Rebuild" IF NOT "!BUILD_TYPE!"=="Clean" ( + call utils\cecho.cmd 0 12 "Invalid build type passed: !BUILD_TYPE!. Cannot proceed, aborting!" + GOTO :Error +) + +:: Make sure deps and install folders exists. +IF NOT EXIST "%DEPS_DIR%". mkdir "%DEPS_DIR%" +IF NOT EXIST "%INSTALL_DIR%". mkdir "%INSTALL_DIR%" + +:: If we use VS2008, framework path (for MSBuild) may not be correctly set. Manually attempt to add in that case +IF %VS_VER%==2008 set PATH=C:\Windows\Microsoft.NET\Framework\v3.5;%PATH% + +:: User-configurable build options +IF NOT DEFINED IFCOS_INSTALL_PYTHON set IFCOS_INSTALL_PYTHON=TRUE + +IF NOT DEFINED IFCOS_NUM_BUILD_PROCS set IFCOS_NUM_BUILD_PROCS=%NUMBER_OF_PROCESSORS% + +:: For subroutines +REM /clp:ErrorsOnly;WarningsOnly +:: Note BUILD_TYPE not passed, Clean e.g. wouldn't delete the installed files. +set MSBUILD_CMD=MSBuild.exe /nologo /m:%IFCOS_NUM_BUILD_PROCS% + +echo. + +:: Check that required tools are in PATH +FOR %%i IN (powershell git cmake) DO ( + where.exe %%i 1> NUL 2> NUL || call cecho.cmd 0 12 "Required tool `'%%i`' not installed or not added to PATH" && goto :ErrorAndPrintUsage +) + +:: Check powershell version +powershell -c "exit $PSVersionTable.PSVersion.Major -lt 5" +IF NOT %ERRORLEVEL%==0 call cecho.cmd 0 12 "Powershell version 5 or higher required" && goto :ErrorAndPrintUsage + +cmake --version | findstr version > temp.txt +set /p CMAKE_VERSION=>"%~dp0\%BUILD_DEPS_CACHE_PATH%" +set OCC_LIBRARY_DIR=%INSTALL_DIR%\opencascade-%OCCT_VERSION%\win%ARCH_BITS%\lib>>"%~dp0\%BUILD_DEPS_CACHE_PATH%" +IF "%IFCOS_INSTALL_PYTHON%"=="TRUE" ( + set PYTHONHOME=%DEPS_DIR%\python.%PYTHON_VERSION%\tools +) + +:: Cache last used CMake generator and configurable dependency dirs for other scripts to use +:: This is consolidated at the beginning of the script so that the script can be partially +:: executed by jumping (using goto) to different labels. +if defined GEN_SHORTHAND echo GEN_SHORTHAND=%GEN_SHORTHAND%>"%~dp0\%BUILD_DEPS_CACHE_PATH%" +echo HDF5_VERSION=%HDF5_VERSION%>>"%~dp0\%BUILD_DEPS_CACHE_PATH%" +echo OCC_INCLUDE_DIR=%OCC_INCLUDE_DIR%>>"%~dp0\%BUILD_DEPS_CACHE_PATH%" +echo OCC_LIBRARY_DIR=%OCC_LIBRARY_DIR%>>"%~dp0\%BUILD_DEPS_CACHE_PATH%" +IF "%IFCOS_INSTALL_PYTHON%"=="TRUE" ( + echo PYTHONHOME=%PYTHONHOME%>>"%~dp0\%BUILD_DEPS_CACHE_PATH%" +) + + +:nuget +set DEPENDENCY_NAME=nuget +set NUGET_VERSION=6.14.0 +set NUGET_INSTALL_DIR=%DEPS_DIR%\nuget-%NUGET_VERSION% +set NUGET_EXE=%NUGET_INSTALL_DIR%\nuget.exe + +where nuget >nul 2>&1 +IF %ERRORLEVEL%==0 ( + echo Found existing nuget in PATH. Skipping. + for /f "delims=" %%i in ('where nuget') do set "NUGET_EXE=%%i" + goto :ccache +) + +IF EXIST "%NUGET_EXE%" ( + echo Found existing "%DEPS_DIR%\nuget.exe", skipping + goto :ccache +) + +cd %DEPS_DIR% +call :DownloadFile ^ + https://dist.nuget.org/win-x86-commandline/v%NUGET_VERSION%/nuget.exe ^ + "%NUGET_INSTALL_DIR%" nuget.exe +IF NOT %ERRORLEVEL%==0 GOTO :Error + + +:ccache +set DEPENDENCY_NAME=ccache +set CCACHE_VERSION=4.12.1 +set CCACHE_INSTALL_DIR=%DEPS_DIR%\%DEPENDENCY_NAME%.%CCACHE_VERSION%\tools +set DEPENDENCY_DIR=%CCACHE_INSTALL_DIR% + +where ccache >nul 2>&1 +IF %ERRORLEVEL%==0 ( + echo Found existing ccache in PATH. Skipping. + goto :proj +) + +echo CCACHE_INSTALL_DIR=%CCACHE_INSTALL_DIR%>>"%~dp0\%BUILD_DEPS_CACHE_PATH%" +IF EXIST "%DEPENDENCY_DIR%" ( + echo Found existing "%DEPENDENCY_DIR%", skipping + goto :proj +) + +"%NUGET_EXE%" install ccache -Version %CCACHE_VERSION% -OutputDirectory "%DEPS_DIR%" +IF NOT %ERRORLEVEL%==0 GOTO :Error + +:proj + +IF NOT DEFINED SKIP_INSTALLED_DEPS_CHECK IF EXIST "%INSTALL_DIR%\proj-9.2.1" ( + echo Found existing "%INSTALL_DIR%\proj-9.2.1", skipping + goto :mpir +) + +set DEPENDENCY_NAME=sqlite3 +md %INSTALL_DIR%\sqlite3\lib %INSTALL_DIR%\sqlite3\bin %INSTALL_DIR%\sqlite3\include +call :DownloadFile https://www.sqlite.org/2023/sqlite-amalgamation-3430100.zip "%DEPS_DIR%" sqlite-amalgamation-3430100.zip +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :ExtractArchive sqlite-amalgamation-3430100.zip "%DEPS_DIR%" "%DEPS_DIR%\sqlite-amalgamation-3430100" +IF NOT %ERRORLEVEL%==0 GOTO :Error +pushd "%DEPS_DIR%\sqlite-amalgamation-3430100" +cl /c sqlite3.c +lib /OUT:%INSTALL_DIR%\sqlite3\lib\sqlite3.lib sqlite3.obj +cl sqlite3.c shell.c /link /out:%INSTALL_DIR%\sqlite3\bin\sqlite3.exe +set PATH=%PATH%;%INSTALL_DIR%\sqlite3\bin +copy sqlite3.h %INSTALL_DIR%\sqlite3\include +popd + +set DEPENDENCY_NAME=proj +set DEPENDENCY_DIR=%DEPS_DIR%\proj-9.2.1 +call :DownloadFile https://download.osgeo.org/proj/proj-9.2.1.zip "%DEPS_DIR%" proj-9.2.1.zip +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :ExtractArchive proj-9.2.1.zip "%DEPS_DIR%" "%DEPS_DIR%\proj-9.2.1" +IF NOT %ERRORLEVEL%==0 GOTO :Error +pushd "%DEPENDENCY_DIR%" +call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\proj-9.2.1" ^ + -DSQLITE3_INCLUDE_DIR=%INSTALL_DIR%\sqlite3\include ^ + -DSQLITE3_LIBRARY=%INSTALL_DIR%\sqlite3\lib\sqlite3.lib ^ + -DENABLE_TIFF=Off -DENABLE_CURL=Off -DBUILD_PROJSYNC=Off ^ + -DBUILD_SHARED_LIBS=Off ^ + -DBUILD_TESTING=Off +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\PROJ.sln" %BUILD_CFG% +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" %BUILD_CFG% +IF NOT %ERRORLEVEL%==0 GOTO :Error +popd + + +:mpir + +IF NOT DEFINED SKIP_INSTALLED_DEPS_CHECK IF EXIST "%INSTALL_DIR%\mpir" ( + echo Found existing "%INSTALL_DIR%\mpir", skipping + goto :mpfr +) + +set DEPENDENCY_NAME=mpir +set DEPENDENCY_DIR=%DEPS_DIR%\mpir +call :GitCloneAndCheckoutRevision https://github.com/BrianGladman/mpir.git "%DEPENDENCY_DIR%" +IF NOT %ERRORLEVEL%==0 GOTO :Error +pushd "%DEPENDENCY_DIR%" +git reset --hard +git clean -fdx +REM There probably need to be quotes here around the filename +powershell -c "get-content %~dp0patches\mpir.patch | %%{$_ -replace \"sdk\",\"%UCRTVersion%\"} | %%{$_ -replace \"fn\",\"lib_mpir_cxx\"}" | git apply --unidiff-zero --ignore-whitespace +IF NOT %ERRORLEVEL%==0 GOTO :Error +powershell -c "get-content %~dp0patches\mpir.patch | %%{$_ -replace \"sdk\",\"%UCRTVersion%\"} | %%{$_ -replace \"fn\",\"lib_mpir_gc\"}" | git apply --unidiff-zero --ignore-whitespace +IF NOT %ERRORLEVEL%==0 GOTO :Error +if NOT "%USE_STATIC_RUNTIME%"=="FALSE" git apply "%~dp0patches\mpir_runtime.patch" --unidiff-zero --ignore-whitespace +IF NOT %ERRORLEVEL%==0 GOTO :Error +cd msvc +cd vs%VS_VER:~2,2% +call .\msbuild.bat gc LIB %VS_PLATFORM% %DEBUG_OR_RELEASE% +IF NOT %ERRORLEVEL%==0 GOTO :Error +IF NOT EXIST "%INSTALL_DIR%\mpir". mkdir "%INSTALL_DIR%\mpir" +copy ..\..\lib\%VS_PLATFORM%\%DEBUG_OR_RELEASE%\* "%INSTALL_DIR%\mpir" +IF NOT %ERRORLEVEL%==0 GOTO :Error +popd + +:mpfr + +IF NOT DEFINED SKIP_INSTALLED_DEPS_CHECK IF EXIST "%INSTALL_DIR%\mpfr" ( + echo Found existing "%INSTALL_DIR%\mpfr", skipping + goto :HDF5 +) + +set DEPENDENCY_NAME=mpfr +set DEPENDENCY_DIR=%DEPS_DIR%\mpfr +call :GitCloneAndCheckoutRevision https://github.com/aothms/mpfr.git "%DEPENDENCY_DIR%" 2ebbe10fd029a480cf6e8a64c493afa9f3654251 +IF NOT %ERRORLEVEL%==0 GOTO :Error +pushd "%DEPENDENCY_DIR%" +git reset --hard +powershell -c "get-content %~dp0patches\mpfr.patch | %%{$_ -replace \"sdk\",\"%UCRTVersion%\"} | %%{$_ -replace \"fn\",\"lib_mpfr\"}" | git apply --unidiff-zero --ignore-whitespace +IF NOT %ERRORLEVEL%==0 GOTO :Error +if NOT "%USE_STATIC_RUNTIME%"=="FALSE" git apply "%~dp0patches\mpfr_runtime.patch" --unidiff-zero --ignore-whitespace +IF NOT %ERRORLEVEL%==0 GOTO :Error +if "%VS_VER%"=="2017" ( + set mpfr_sln=build.vc15 + set orig_platform_toolset=v141 +) else ( + set mpfr_sln=build.vs19 + set orig_platform_toolset=v142 +) +powershell -c "get-childitem %DEPENDENCY_DIR%\%mpfr_sln% -recurse -include *.vcxproj | select -expand fullname | foreach { (Get-Content $_) -replace '%orig_platform_toolset%', 'v%VC_VER:.=%' | Set-Content $_ }" +call :BuildSolution "%DEPENDENCY_DIR%\%mpfr_sln%\lib_mpfr.sln" %DEBUG_OR_RELEASE% lib_mpfr +IF NOT %ERRORLEVEL%==0 GOTO :Error +REM This command fails because not all msvc projects are patched with the right sdk version +IF NOT EXIST lib\%VS_PLATFORM%\%DEBUG_OR_RELEASE%\mpfr.lib GOTO :Error +IF NOT EXIST "%INSTALL_DIR%\mpfr". mkdir "%INSTALL_DIR%\mpfr" +copy lib\%VS_PLATFORM%\%DEBUG_OR_RELEASE%\* "%INSTALL_DIR%\mpfr" +IF NOT %ERRORLEVEL%==0 GOTO :Error +popd + +:HDF5 + +set DEPENDENCY_NAME=hdf5 +set DEPENDENCY_DIR=%DEPS_DIR%\hdf5-%HDF5_VERSION% +set HDF5_CMAKE_ZIP=hdf5-%HDF5_VERSION%.zip +set HDF5_INSTALL_NAME=HDF5-%HDF5_VERSION%-win%ARCH_BITS% + +IF NOT DEFINED SKIP_INSTALLED_DEPS_CHECK IF EXIST "%INSTALL_DIR%\%HDF5_INSTALL_NAME%" ( + echo Found existing "%INSTALL_DIR%\%HDF5_INSTALL_NAME%", skipping + goto :Boost +) + +if "%ARCH_BITS%"=="64" set ARCH_BITS_64=64 +call :DownloadFile ^ + https://github.com/HDFGroup/hdf5/archive/refs/tags/hdf5-%HDF5_VERSION%.zip ^ + "%DEPS_DIR%" %HDF5_CMAKE_ZIP% +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :ExtractArchive %HDF5_CMAKE_ZIP% "%DEPS_DIR%" "%DEPS_DIR%\hdf5-%HDF5_VERSION%" +IF NOT %ERRORLEVEL%==0 GOTO :Error +if exist "%DEPS_DIR%\hdf5-hdf5-%HDF5_VERSION%" ren "%DEPS_DIR%\hdf5-hdf5-%HDF5_VERSION%" "hdf5-%HDF5_VERSION%" +pushd "%DEPENDENCY_DIR%" +call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\%HDF5_INSTALL_NAME%" ^ + -DHDF5_ENABLE_Z_LIB_SUPPORT=OFF -DBUILD_TESTING=OFF ^ + -DHDF5_BUILD_TOOLS=OFF -DHDF5_BUILD_EXAMPLES=OFF -DBUILD_SHARED_LIBS=OFF -DHDF5_BUILD_UTILS=OFF ^ + -DHDF5_BUILD_CPP_LIB=ON +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\HDF5.sln" %DEBUG_OR_RELEASE% +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" %DEBUG_OR_RELEASE% +IF NOT %ERRORLEVEL%==0 GOTO :Error +popd + +:: Note all of the dependencies have appropriate label so that user can easily skip something if wanted +:: by modifying this file and using goto. +:Boost +:: DEPENDENCY_NAME is used for logging and DEPENDENCY_DIR for saving from some redundant typing +set DEPENDENCY_NAME=Boost %BOOST_VERSION% +set DEPENDENCY_DIR=%DEPS_DIR%\boost_%BOOST_VER% +set DEPENDENCY_INSTALL_DIR=%DEPENDENCY_DIR%\stage\%GEN_SHORTHAND% +echo BOOST_INSTALL_DIR=%DEPENDENCY_INSTALL_DIR%>>"%~dp0\%BUILD_DEPS_CACHE_PATH%" +:: Needed for CGAL build. +set BOOST_ROOT=%DEPENDENCY_DIR% +set BOOST_LIBRARYDIR=%DEPENDENCY_DIR%\stage\%GEN_SHORTHAND%\lib +:: NOTE Also zip download exists, if encountering problems with 7z for some reason. +set ZIP_EXT=7z +set BOOST_ZIP=boost-%BOOST_VERSION%-b2-nodocs.%ZIP_EXT% + +cd "%DEPS_DIR%" +call :DownloadFile https://github.com/boostorg/boost/releases/download/boost-%BOOST_VERSION%/%BOOST_ZIP% "%DEPS_DIR%" %BOOST_ZIP% + +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :ExtractArchive %BOOST_ZIP% "%DEPS_DIR%" %DEPENDENCY_DIR% +IF NOT %ERRORLEVEL%==0 GOTO :Error + +:: top-level folder name changed when migrating to github releases +if exist "%DEPS_DIR%\boost-%BOOST_VERSION%". ( + ren %DEPS_DIR%\boost-%BOOST_VERSION% boost_%BOOST_VER% +) + +:: Build Boost build script +if not exist "%DEPENDENCY_DIR%\project-config.jam". ( + cd "%DEPS_DIR%" + IF NOT EXIST "%DEPENDENCY_DIR%\boost.css" GOTO :Error + cd "%DEPENDENCY_DIR%" + call cecho.cmd 0 13 "Building Boost build script." + call bootstrap %BOOST_BOOTSTRAP_VER% + IF NOT %ERRORLEVEL%==0 GOTO :Error +) + +set BOOST_LIBS=--with-system --with-regex --with-thread --with-program_options --with-date_time --with-iostreams --with-filesystem +:: NOTE Boost is fast to build with limited set of libraries so build it always. +cd "%DEPENDENCY_DIR%" +call cecho.cmd 0 13 "Building %DEPENDENCY_NAME% %BOOST_LIBS% Please be patient, this will take a while." +IF EXIST "%DEPENDENCY_DIR%\bin.v2\project-cache.jam" del "%DEPENDENCY_DIR%\bin.v2\project-cache.jam" + +call .\b2 toolset=%BOOST_TOOLSET% runtime-link=shared address-model=%ARCH_BITS% --abbreviate-paths -j%IFCOS_NUM_BUILD_PROCS% ^ + variant=%DEBUG_OR_RELEASE_LOWERCASE% %BOOST_WIN_API% %BOOST_LIBS% stage --stagedir=%DEPENDENCY_INSTALL_DIR% + +IF NOT %ERRORLEVEL%==0 GOTO :Error + +:JSON +set DEPENDENCY_NAME=JSON for Modern C++ v%JSON_VERSION% +IF NOT EXIST "%INSTALL_DIR%\json\nlohmann". mkdir "%INSTALL_DIR%\json\nlohmann" +call :DownloadFile https://github.com/nlohmann/json/releases/download/v%JSON_VERSION%/json.hpp "%INSTALL_DIR%\json\nlohmann" json.hpp + +:OpenCOLLADA + +:: Note OpenCOLLADA has only Release and Debug builds. +set DEPENDENCY_NAME=OpenCOLLADA +set DEPENDENCY_DIR=%DEPS_DIR%\OpenCOLLADA +:: Always clone it, even if it's installed, because it contains xml headers we need. +:: Use a fixed revision in order to prevent introducing breaking changes +call :GitCloneAndCheckoutRevision https://github.com/KhronosGroup/OpenCOLLADA.git "%DEPENDENCY_DIR%" %OPENCOLLADA_VERSION% + +IF NOT DEFINED SKIP_INSTALLED_DEPS_CHECK IF EXIST "%INSTALL_DIR%\OpenCOLLADA" ( + echo Found existing "%INSTALL_DIR%\OpenCOLLADA", skipping + :: we do need to clone though because the bundled libxml includes are not installed + goto :OCCT +) + +IF NOT %ERRORLEVEL%==0 GOTO :Error +cd "%DEPENDENCY_DIR%" +:: Debug build of OpenCOLLADAValidator fails (https://github.com/KhronosGroup/OpenCOLLADA/issues/377) so +:: so disable it from the build altogether as we have no use for it +findstr #add_subdirectory(COLLADAValidator) CMakeLists.txt>NUL +IF NOT %ERRORLEVEL%==0 git apply --reject --whitespace=fix "%~dp0patches\OpenCOLLADA_CMakeLists.txt.patch" --ignore-whitespace +:: NOTE OpenCOLLADA has been observed to have problems with switching between debug and release builds so +:: uncomment to following line in order to delete the CMakeCache.txt always if experiencing problems. +REM IF EXIST "%DEPENDENCY_DIR%\%BUILD_DIR%\CMakeCache.txt". del "%DEPENDENCY_DIR%\%BUILD_DIR%\CMakeCache.txt" +:: NOTE Enforce that the embedded LibXml2 and PCRE are used as there might be problems with arbitrary versions of the libraries. +call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\OpenCOLLADA" -DUSE_STATIC_MSVC_RUNTIME=0 -DCMAKE_DEBUG_POSTFIX=d ^ + -DLIBXML2_LIBRARIES="" -DLIBXML2_INCLUDE_DIR="" -DPCRE_INCLUDE_DIR="" -DPCRE_LIBRARIES="" +IF NOT %ERRORLEVEL%==0 GOTO :Error +REM IF NOT EXIST "%DEPS_DIR%\OpenCOLLADA\%BUILD_DIR%\lib\%DEBUG_OR_RELEASE%\OpenCOLLADASaxFrameworkLoader.lib". +call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\OPENCOLLADA.sln" %DEBUG_OR_RELEASE% +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" %DEBUG_OR_RELEASE% +IF NOT %ERRORLEVEL%==0 GOTO :Error + +:OCCT + +SET OCCT_VER=V%OCCT_VERSION:.=_% + +IF NOT DEFINED SKIP_INSTALLED_DEPS_CHECK IF EXIST "%INSTALL_DIR%\opencascade-%OCCT_VERSION%" ( + echo Found existing "%INSTALL_DIR%\opencascade-%OCCT_VERSION%", skipping + goto :Python +) + +:: OCCT has many dependencies but FreeType is the only mandatory +set DEPENDENCY_NAME=FreeType +set DEPENDENCY_DIR=%DEPS_DIR%\freetype-2.7.1 +set FREETYPE_ZIP=VER-2-7-1.zip +cd "%DEPS_DIR%" +call :DownloadFile https://github.com/freetype/freetype/archive/refs/tags/%FREETYPE_ZIP% "%DEPS_DIR%" %FREETYPE_ZIP% +if not %ERRORLEVEL%==0 goto :Error +call :ExtractArchive %FREETYPE_ZIP% "%DEPS_DIR%" "%DEPENDENCY_DIR%" +if not %ERRORLEVEL%==0 goto :Error +if exist "%DEPS_DIR%\freetype-VER-2-7-1" ren "%DEPS_DIR%\freetype-VER-2-7-1" "freetype-2.7.1" +cd "%DEPENDENCY_DIR%" +:: NOTE FreeType is built as a static library by default +call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\freetype" +if not %ERRORLEVEL%==0 goto :Error +call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\freetype.sln" %BUILD_CFG% +if not %ERRORLEVEL%==0 goto :Error +call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" %BUILD_CFG% +if not %ERRORLEVEL%==0 goto :Error + +set DEPENDENCY_NAME=Open CASCADE %OCCT_VERSION% +set DEPENDENCY_DIR=%DEPS_DIR%\occt_git +cd "%DEPS_DIR%" +call :GitCloneAndCheckoutRevision https://github.com/Open-Cascade-SAS/OCCT "%DEPENDENCY_DIR%" %OCCT_VER% +if not %ERRORLEVEL%==0 goto :Error + +:: Patching always blindly would trigger a rebuild each time +findstr IfcOpenShell "%DEPENDENCY_DIR%\CMakeLists.txt">NUL +if not %ERRORLEVEL%==0 ( + pushd "%DEPENDENCY_DIR%" + git apply --ignore-whitespace ""%~dp0patches\%OCCT_VER%.patch" + popd +) +findstr IfcOpenShell "%DEPENDENCY_DIR%\CMakeLists.txt">NUL +if not %ERRORLEVEL%==0 goto :Error + +cd "%DEPENDENCY_DIR%" +call :RunCMake -DINSTALL_DIR="%INSTALL_DIR%\opencascade-%OCCT_VERSION%" -DBUILD_LIBRARY_TYPE="Static" -DCMAKE_DEBUG_POSTFIX=d ^ + -DBUILD_MODULE_Draw=0 -D3RDPARTY_FREETYPE_DIR="%INSTALL_DIR%\freetype" +if not %ERRORLEVEL%==0 goto :Error + +:: whole program optimization avoids Visual C++ hanging when compiling 32-bit release OCCT up to version 7.4.0 +IF %ARCH_BITS%==32 ( + IF %BUILD_CFG%==Release ( + SET COMPILE_WITH_WPO=TRUE + ) +) + +call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\OCCT.sln" %BUILD_CFG% +if not %ERRORLEVEL%==0 goto :Error +call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" %BUILD_CFG% +if not %ERRORLEVEL%==0 goto :Error + +SET COMPILE_WITH_WPO=FALSE + +:: Use a single lib directory for release and debug libraries as is done with OCE +if not exist "%OCC_LIBRARY_DIR%". mkdir "%OCC_LIBRARY_DIR%" +:: NOTE OCCT (at least occt-V7_0_0-9059ca1) directory creation code is hardcoded and doesn't seem handle future VC versions +set OCCT_VC_VER=%VC_VER% +IF %OCCT_VC_VER% GTR 14 ( + set OCCT_VC_VER=14 +) +move /y "%INSTALL_DIR%\opencascade-%OCCT_VERSION%\win%ARCH_BITS%\vc%OCCT_VC_VER%\libi\*.*" "%OCC_LIBRARY_DIR%" +move /y "%INSTALL_DIR%\opencascade-%OCCT_VERSION%\win%ARCH_BITS%\vc%OCCT_VC_VER%\libd\*.*" "%OCC_LIBRARY_DIR%" +move /y "%INSTALL_DIR%\opencascade-%OCCT_VERSION%\win%ARCH_BITS%\vc%OCCT_VC_VER%\lib\*.*" "%OCC_LIBRARY_DIR%" +rmdir /s /q "%INSTALL_DIR%\opencascade-%OCCT_VERSION%\win%ARCH_BITS%\vc%OCCT_VC_VER%" +:: Removed unneeded bits +rmdir /s /q "%INSTALL_DIR%\opencascade-%OCCT_VERSION%\data" +rmdir /s /q "%INSTALL_DIR%\opencascade-%OCCT_VERSION%\samples" +del "%INSTALL_DIR%\opencascade-%OCCT_VERSION%\*.bat" + +:Python +set DEPENDENCY_NAME=Python %PYTHON_VERSION% +set DEPENDENCY_DIR=N/A +set PYTHON_AMD64_POSTFIX=-amd64 +IF NOT %TARGET_ARCH%==x64 set PYTHON_AMD64_POSTFIX= +set PYTHON_INSTALLER=python-%PYTHON_VERSION%%PYTHON_AMD64_POSTFIX%.exe + +IF NOT "%IFCOS_INSTALL_PYTHON%"=="TRUE" ( + call cecho.cmd 0 13 "IFCOS_INSTALL_PYTHON not 'TRUE', skipping installation of Python." + goto :SWIG +) + +:: nuget doesn't support providing architecture for packages. +if NOT %TARGET_ARCH%==x64 ( + call cecho.cmd 0 12 "Automatic insallation of Python for x86 builds is not supported," + call cecho.cmd 0 12 "please install Python %PYTHON_VERSION% manually and ensure that it is available in PATH." + call cecho.cmd 0 12 "https://www.python.org/ftp/python/%PYTHON_VERSION%/%PYTHON_INSTALLER%" + goto :Error +) + + +if EXIST "%PYTHONHOME%" ( + echo Found existing '%PYTHONHOME%', skipping installation. + goto :SWIG +) + +"%NUGET_EXE%" install Python -Version %PYTHON_VERSION% -OutputDirectory "%DEPS_DIR%" +IF NOT %ERRORLEVEL%==0 GOTO :Error + + +:SWIG +set DEPENDENCY_NAME=SWIG +set SWIG_VERSION=4.1.0 +set DEPENDENCY_DIR=%DEPS_DIR%\swig-%SWIG_VERSION% +set DEPENDENCY_INSTALL_DIR=%INSTALL_DIR%\swig-%SWIG_VERSION% +echo SWIG_INSTALL_DIR=%DEPENDENCY_INSTALL_DIR%>>"%~dp0\%BUILD_DEPS_CACHE_PATH%" + +IF NOT DEFINED SKIP_INSTALLED_DEPS_CHECK IF EXIST "%DEPENDENCY_INSTALL_DIR%" ( + echo Found existing "%DEPENDENCY_INSTALL_DIR%", skipping + goto :cgal +) + +cd "%DEPS_DIR%" + +:: Install bizon dependency for SWIG. +set SWIG_DEPENDENCY_NAME=%DEPENDENCY_NAME% +set DEPENDENCY_NAME=win_flex_bison +set WIN_FLEX_BIZON=win_flex_bison-2.5.25 +set WIN_FLEX_BIZON_ZIP=%WIN_FLEX_BIZON%.zip +call :DownloadFile https://github.com/lexxmark/winflexbison/releases/download/v2.5.25/%WIN_FLEX_BIZON_ZIP% "%DEPS_DIR%" %WIN_FLEX_BIZON_ZIP% +IF NOT %ERRORLEVEL%==0 GOTO :Error +echo test %WIN_FLEX_BIZON% +call :ExtractArchive %WIN_FLEX_BIZON_ZIP% "%DEPS_DIR%\%WIN_FLEX_BIZON%" "%DEPS_DIR%\%WIN_FLEX_BIZON%" +IF NOT %ERRORLEVEL%==0 GOTO :Error +set DEPENDENCY_NAME=%SWIG_DEPENDENCY_NAME% + +set SWIG_ZIP=swigwin-%SWIG_VERSION%.zip +call :DownloadFile https://github.com/swig/swig/archive/refs/tags/v%SWIG_VERSION%.zip "%DEPS_DIR%" swig-%SWIG_VERSION%.zip +IF NOT %ERRORLEVEL%==0 GOTO :Error + +call :ExtractArchive swig-%SWIG_VERSION%.zip "%DEPS_DIR%" "%DEPENDENCY_DIR%" +IF NOT %ERRORLEVEL%==0 GOTO :Error +cd "%DEPENDENCY_DIR%" + +call :RunCMake -DCMAKE_INSTALL_PREFIX="%DEPENDENCY_INSTALL_DIR%" ^ + -DWITH_PCRE=OFF ^ + -DBISON_EXECUTABLE="%DEPS_DIR%\%WIN_FLEX_BIZON%\win_bison.exe" +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\swig.sln" Release +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" Release +IF NOT %ERRORLEVEL%==0 GOTO :Error +robocopy "%INSTALL_DIR%\swigwin\bin" "%INSTALL_DIR%\swigwin" /move /e + +:cgal + +IF NOT DEFINED SKIP_INSTALLED_DEPS_CHECK IF EXIST "%INSTALL_DIR%\cgal" ( + echo Found existing "%INSTALL_DIR%\cgal", skipping + goto :Eigen +) + +set DEPENDENCY_NAME=cgal +set DEPENDENCY_DIR=%DEPS_DIR%\cgal +call :GitCloneAndCheckoutRevision https://github.com/CGAL/cgal.git "%DEPENDENCY_DIR%" %CGAL_VERSION% +IF NOT %ERRORLEVEL%==0 GOTO :Error +cd "%DEPENDENCY_DIR%" +git reset --hard +git apply --ignore-whitespace "%~dp0patches\cgal_no_zlib.patch" +call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\cgal" ^ + -DBOOST_ROOT="%BOOST_ROOT%" ^ + -DGMP_INCLUDE_DIR="%INSTALL_DIR%\mpir" ^ + -DGMP_LIBRARIES="%INSTALL_DIR%\mpir\mpir.lib" ^ + -DMPFR_INCLUDE_DIR="%INSTALL_DIR%\mpfr" ^ + -DMPFR_LIBRARIES="%INSTALL_DIR%\mpfr\mpfr.lib" ^ + -DCGAL_HEADER_ONLY=On ^ + -DBOOST_LIBRARYDIR="%BOOST_LIBRARYDIR%" +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\CGAL.sln" %BUILD_CFG% +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" %BUILD_CFG% +IF NOT %ERRORLEVEL%==0 GOTO :Error + +:Eigen +set DEPENDENCY_NAME=Eigen +set DEPENDENCY_DIR=%INSTALL_DIR%\%DEPENDENCY_NAME% + +IF NOT DEFINED SKIP_INSTALLED_DEPS_CHECK IF EXIST "%INSTALL_DIR%\%DEPENDENCY_NAME%" ( + echo Found existing "%INSTALL_DIR%\%DEPENDENCY_NAME%", skipping + goto :zstd +) +call :GitCloneAndCheckoutRevision https://gitlab.com/libeigen/eigen.git "%DEPENDENCY_DIR%" %EIGEN_VERSION% + +:zstd +set DEPENDENCY_NAME=zstd +set ZSTD_VERSION=1.5.7 +set ZSTD_ZIP=zstd-%ZSTD_VERSION%.zip +set DEPENDENCY_DIR=%DEPS_DIR%\%DEPENDENCY_NAME%-%ZSTD_VERSION% + +IF NOT DEFINED SKIP_INSTALLED_DEPS_CHECK IF EXIST "%INSTALL_DIR%\%DEPENDENCY_NAME%" ( + echo Found existing "%INSTALL_DIR%\%DEPENDENCY_NAME%", skipping + goto :rocksdb +) + +cd %DEPS_DIR% +call :DownloadFile ^ + https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD_VERSION%.zip ^ + "%DEPS_DIR%" %ZSTD_ZIP% +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :ExtractArchive %ZSTD_ZIP% "%DEPS_DIR%" "%DEPENDENCY_DIR%" +IF NOT %ERRORLEVEL%==0 GOTO :Error +cd "%DEPENDENCY_DIR%"\build\cmake +call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\zstd" -DZSTD_BUILD_STATIC=ON -DZSTD_BUILD_SHARED=OFF +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :BuildSolution "%DEPENDENCY_DIR%\build\cmake\%BUILD_DIR%\zstd.sln" %BUILD_CFG% +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :InstallCMakeProject "%DEPENDENCY_DIR%\build\cmake\%BUILD_DIR%" %BUILD_CFG% +IF NOT %ERRORLEVEL%==0 GOTO :Error + +:rocksdb +set DEPENDENCY_NAME=rocksdb +set ROCKSDB_VERSION=9.11.2 +set ROCKSDB_ZIP=rocksdb-%ROCKSDB_VERSION%.zip +set DEPENDENCY_DIR=%DEPS_DIR%\%DEPENDENCY_NAME%-%ROCKSDB_VERSION% + +IF NOT DEFINED SKIP_INSTALLED_DEPS_CHECK IF EXIST "%INSTALL_DIR%\%DEPENDENCY_NAME%" ( + echo Found existing "%INSTALL_DIR%\%DEPENDENCY_NAME%", skipping + goto :Successful +) + +cd %DEPS_DIR% +call :DownloadFile ^ + https://github.com/facebook/rocksdb/archive/refs/tags/v%ROCKSDB_VERSION%.zip ^ + "%DEPS_DIR%" %ROCKSDB_ZIP% +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :ExtractArchive %ROCKSDB_ZIP% "%DEPS_DIR%" "%DEPENDENCY_DIR%" +IF NOT %ERRORLEVEL%==0 GOTO :Error +cd "%DEPENDENCY_DIR%" +:: see rocksdb\thirdparty.inc +:: providing package is not supported on Windows. +set ZSTD_INCLUDE=%INSTALL_DIR%\zstd\include +set ZSTD_LIB_DEBUG=%INSTALL_DIR%\zstd\lib\zstd_static.lib +set ZSTD_LIB_RELEASE=%INSTALL_DIR%\zstd\lib\zstd_static.lib +call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\rocksdb" ^ + -DROCKSDB_INSTALL_ON_WINDOWS=On ^ + -DFAIL_ON_WARNINGS=Off ^ + -DWITH_TESTS=OFF ^ + -DWITH_ZSTD=On ^ + -DPORTABLE=1 +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\rocksdb.sln" %BUILD_CFG% +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" %BUILD_CFG% +IF NOT %ERRORLEVEL%==0 GOTO :Error + +:: :tbb +:: set DEPENDENCY_NAME=tbb +:: set DEPENDENCY_DIR=%DEPS_DIR%\tbb +:: call :GitCloneAndCheckoutRevision https://github.com/wjakob/tbb "%DEPENDENCY_DIR%" 9e219e24fe223b299783200f217e9d27790a87b0 +:: IF NOT %ERRORLEVEL%==0 GOTO :Error +:: cd "%DEPENDENCY_DIR%" +:: call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\tbb" ^ +:: -DBUILD_SHARED_LIBS=Off +:: IF NOT %ERRORLEVEL%==0 GOTO :Error +:: call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\TBB.sln" %BUILD_CFG% +:: IF NOT %ERRORLEVEL%==0 GOTO :Error +:: call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" %BUILD_CFG% +:: IF NOT %ERRORLEVEL%==0 GOTO :Error +:: +:: :usd +:: set DEPENDENCY_NAME=usd +:: set DEPENDENCY_DIR=%DEPS_DIR%\usd +:: call :GitCloneAndCheckoutRevision https://github.com/PixarAnimationStudios/OpenUSD "%DEPENDENCY_DIR%" v24.05 +:: IF NOT %ERRORLEVEL%==0 GOTO :Error +:: cd "%DEPENDENCY_DIR%" +:: call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\usd" ^ +:: -DBOOST_ROOT="%DEPS_DIR%\boost_%BOOST_VER%" ^ +:: -DOneTBB_CMAKE_ENABLE=On ^ +:: -DTBB_ROOT_DIR="%INSTALL_DIR%\tbb" ^ +:: -DPXR_ENABLE_PYTHON_SUPPORT=FALSE ^ +:: -DPXR_ENABLE_GL_SUPPORT=FALSE ^ +:: -DPXR_BUILD_IMAGING=FALSE ^ +:: -DPXR_BUILD_TUTORIALS=FALSE ^ +:: -DPXR_BUILD_EXAMPLES=FALSE ^ +:: -DPXR_BUILD_USD_TOOLS=FALSE ^ +:: -DPXR_BUILD_TESTS=FALSE ^ +:: -DBUILD_SHARED_LIBS=Off ^ +:: -DBOOST_LIBRARYDIR="%DEPS_DIR%\boost_%BOOST_VER%\stage\vs%VS_VER%-%VS_PLATFORM%\lib" +:: IF NOT %ERRORLEVEL%==0 GOTO :Error +:: call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\USD.sln" %BUILD_CFG% +:: IF NOT %ERRORLEVEL%==0 GOTO :Error +:: call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" %BUILD_CFG% +:: IF NOT %ERRORLEVEL%==0 GOTO :Error + +:Successful +echo. +call "%~dp0\utils\cecho.cmd" 0 10 "%PROJECT_NAME% dependencies built." +set IFCOS_SCRIPT_RET=0 +goto :Finish + +:ErrorAndPrintUsage +echo. +call :PrintUsage +:Error +echo. +call "%~dp0\utils\cecho.cmd" 0 12 "An error occurred! Aborting! Last logged action: %LAST_ACTION%" +set IFCOS_SCRIPT_RET=1 +goto :Finish + +:Finish +:: Print end time and elapsed time, http://stackoverflow.com/a/9935540 +if not defined BUILD_STARTED goto :BuildTimeSkipped +set END_TIME=%TIME% +for /F "tokens=1-4 delims=:.," %%a in ("%START_TIME%") do ( + set /A "start=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100" +) +for /F "tokens=1-4 delims=:.," %%a in ("%END_TIME%") do ( + set /A "end=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100" +) +set /A elapsed=end-start +set /A hh=elapsed/(60*60*100), rest=elapsed%%(60*60*100), mm=rest/(60*100), rest%%=60*100, ss=rest/100, cc=rest%%100 +if %mm% lss 10 set mm=0%mm% +if %ss% lss 10 set ss=0%ss% +if %cc% lss 10 set cc=0%cc% +echo. +echo Build ended at %END_TIME%. Time elapsed %hh%:%mm%:%ss%.%cc%. +:BuildTimeSkipped +set PATH=%ORIGINAL_PATH% +cd "%~dp0" +exit /b %IFCOS_SCRIPT_RET% + +::::::::::::::::::::::::::::::::::::: Subroutines ::::::::::::::::::::::::::::::::::::: + +:: DownloadFile - Downloads a file using PowerShell +:: Params: %1 url, %2 destinationDir, %3 filename +:DownloadFile +mkdir "%2" +pushd "%2" +if not exist "%~3". ( + call cecho.cmd 0 13 "Downloading %DEPENDENCY_NAME% into %~2." + powershell -Command "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; $webClient = new-object System.Net.WebClient; $webClient.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials; $webClient.DownloadFile('%1', '%3')" + REM Old wget version in case someone has problem with PowerShell: wget --no-check-certificate %1 +) else ( + call cecho.cmd 0 13 "%DEPENDENCY_NAME% already downloaded. Skipping." +) +set RET=%ERRORLEVEL% +set LAST_ACTION=DownloadFile '%DEPENDENCY_NAME%'. +popd +exit /b %RET% + +:: ExtractArchive - Extracts an archive file using 7-zip +:: Params: %1 filename, %2 destinationDir, %3 dirAfterExtraction +:ExtractArchive +if not exist "%~3". ( + call cecho.cmd 0 13 "Extracting %DEPENDENCY_NAME% into %~2 from %1" + 7za x %1 -y -o%2 > nul +) else ( + call cecho.cmd 0 13 "%DEPENDENCY_NAME% already extracted into %~3. Skipping." +) +set RET=%ERRORLEVEL% +set LAST_ACTION=ExtractArchive '%DEPENDENCY_NAME%'. +exit /b %RET% + +:: GitCloneOrPullRepository - Clones or pulls (if repository already cloned) a Git repository +:: Params: %1 gitUrl, %2 destDir +:: F.ex. call :GitCloneRepository https://github.com/KhronosGroup/OpenCOLLADA.git "%DEPS_DIR%\OpenCOLLADA\" +:GitCloneOrPullRepository +if not exist "%~2". ( + call cecho.cmd 0 13 "Cloning %DEPENDENCY_NAME% into %~2." + pushd "%DEPS_DIR%" + call git clone %1 %2 + set RET=!ERRORLEVEL! +) else ( + call cecho.cmd 0 13 "%DEPENDENCY_NAME% already cloned. Pulling latest changes." + git reset --hard + pushd %2 + call git pull + set RET=0 +) +popd +exit /b %RET% + +:: GitCloneAndCheckoutRevision - Clones a Git repository and checks out a specific revision or tag +:: Params: %1 gitUrl, %2 destDir, %3 revision +:: F.ex. call :GitCloneAndCheckoutRevision https://github.com/KhronosGroup/OpenCOLLADA.git "%DEPENDENCY_DIR%" 064a60b65c2c31b94f013820856bc84fb1937cc6 +:GitCloneAndCheckoutRevision +if not exist "%~2". ( + call cecho.cmd 0 13 "Cloning %DEPENDENCY_NAME% into %~2." + pushd "%DEPS_DIR%" + call git clone %1 %2 + set RET=!ERRORLEVEL! + if not "!RET!"=="0" exit /b !RET! + popd +) else ( + call cecho.cmd 0 13 "%DEPENDENCY_NAME% already cloned." + set RET=0 +) +pushd "%2" +call git fetch +call cecho.cmd 0 13 "Checking out %DEPENDENCY_NAME% revision %3." +call git reset --hard +call git checkout %3 +set RET=%ERRORLEVEL% +popd +exit /b %RET% + +:: RunCMake - Runs CMake for a CMake-based project +:: Params: %* cmakeOptions +:: NOTE cd to root CMakeLists.txt folder before calling this if the CMakeLists.txt is not in the repo root. +:RunCMake +call cecho.cmd 0 13 "Running CMake for %DEPENDENCY_NAME%." +IF NOT EXIST %BUILD_DIR%. mkdir %BUILD_DIR% +IF NOT %ERRORLEVEL%==0 GOTO :Error +pushd %BUILD_DIR% +:: TODO make deleting cache a parameter for this subroutine? We probably want to delete the +:: cache always e.g. when we've had new changes in the repository. +IF %BUILD_TYPE%==Rebuild IF EXIST CMakeCache.txt. del CMakeCache.txt + +IF NOT "%VS_TOOLSET_HOST%"=="" ( + cmake .. -G %GENERATOR% -A %VS_PLATFORM% -T %VS_TOOLSET_HOST% %* +) ELSE ( + cmake .. -G %GENERATOR% -A %VS_PLATFORM% %* +) + +set RET=%ERRORLEVEL% +popd +exit /b %RET% + +:: TODO add BuildCMakeProject which utilizes cmake --build + +:: BuildSolution - Builds/Rebuilds/Cleans a solution using MSBuild +:: Params: %1 solutioName, %2 configuration +:BuildSolution +IF [%~3]==[] ( + set TARGET=%BUILD_TYPE% +) ELSE ( + IF /I %BUILD_TYPE%==Build ( + set TARGET="%3" + ) ELSE ( + set TARGET="%3:%BUILD_TYPE%" + ) +) + +call cecho.cmd 0 13 "Building %TARGET% of %DEPENDENCY_NAME%. Please be patient, this will take a while." + +:: whole program optimization avoids Visual C++ hanging when compiling 32-bit release OCCT up to version 7.4.0 +IF %COMPILE_WITH_WPO%==FALSE ( + %MSBUILD_CMD% %1 /p:configuration=%2;platform=%VS_PLATFORM% /t:"%TARGET%" +) ELSE ( + %MSBUILD_CMD% %1 /p:configuration=%2;platform=%VS_PLATFORM%;WholeProgramOptimization=TRUE /t:"%TARGET%" +) +exit /b %ERRORLEVEL% + +:: InstallCMakeProject - Builds the INSTALL project of CMake-based project +:: Params: %1 buildDir, %2 == configuration +:: NOTE the actual install dir is set during cmake run. +:: TODO Utilize cmake --build --target INSTALL +:InstallCMakeProject +pushd %1 +call cecho.cmd 0 13 "Installing %2 %DEPENDENCY_NAME%. Please be patient, this will take a while." + +:: whole program optimization avoids Visual C++ hanging when compiling 32-bit release OCCT up to version 7.4.0 +IF %COMPILE_WITH_WPO%==FALSE ( + %MSBUILD_CMD% INSTALL.%VCPROJ_FILE_EXT% /p:configuration=%2;platform=%VS_PLATFORM% +) ELSE ( + %MSBUILD_CMD% INSTALL.%VCPROJ_FILE_EXT% /p:configuration=%2;platform=%VS_PLATFORM%;WholeProgramOptimization=TRUE +) +set RET=%ERRORLEVEL% +popd +exit /b %RET% + +:: PrintUsage - Prints usage information +:PrintUsage +call "%~dp0\utils\cecho.cmd" 0 10 "Requirements for a successful execution:" +echo 1. Install PowerShell (preinstalled in Windows ^>= 7) version 5 or higher and make sure 'powershell' is accessible from PATH. +echo - https://support.microsoft.com/en-us/kb/968929 +echo 2. Install Git and make sure 'git' is accessible from PATH. +echo - https://git-for-windows.github.io/ +echo 3. Install CMake and make sure 'cmake' is accessible from PATH. +echo - http://www.cmake.org/ +echo 4. Visual Studio 2013 or newer with C++ toolset. +echo - https://www.visualstudio.com/ +echo 5. Run this batch script with Visual Studio environment variables set. +echo - https://msdn.microsoft.com/en-us/library/ms229859(v=vs.110).aspx +echo. +echo NB: This script needs to be ran from the directory directly containing it. +echo. From ba2f48e210aeca30c6b1ed18dfd5c3cc5f6b3568 Mon Sep 17 00:00:00 2001 From: Josef Wienerroither Date: Mon, 8 Dec 2025 16:12:18 +0100 Subject: [PATCH 5/5] refactor: improve string conversions --- src/ifcmax/IfcMax.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/ifcmax/IfcMax.cpp b/src/ifcmax/IfcMax.cpp index 638c44cfd3..35d19e096a 100644 --- a/src/ifcmax/IfcMax.cpp +++ b/src/ifcmax/IfcMax.cpp @@ -391,10 +391,10 @@ int IFCImp::DoImport(const TCHAR *file_name, ImpInterface *impitfc, Interface *i const IfcGeom::BRepElement* brepElement = static_cast(iterator.get_native()); const IfcGeom::TriangulationElement* triElement = static_cast(iterator.get()); - const TSTR e_type = TSTR::FromUTF8(element->type().c_str()); - const TSTR e_guid = TSTR::FromUTF8(element->guid().c_str()); - const TSTR e_name = TSTR::FromUTF8(element->name().c_str()); - const TSTR e_idStr = TSTR(std::to_wstring(element->id()).c_str()); + TSTR e_type = TSTR::FromUTF8(element->type().c_str()); + TSTR e_guid = TSTR::FromUTF8(element->guid().c_str()); + TSTR e_name = TSTR::FromUTF8(element->name().c_str()); + TSTR e_idStr = TSTR(std::to_wstring(element->id()).c_str()); // dump out the parent tree up to IfcProject for each element @@ -406,8 +406,8 @@ int IFCImp::DoImport(const TCHAR *file_name, ImpInterface *impitfc, Interface *i log_stream << "->" << p_e->type() << " [#" << p_e->id() << "]"; } } - - LogToListener(_M("%3d%% - [#%d] %s: '%s' %s\n"), iterator.progress(), element->id(), e_type, e_name, TSTR::FromUTF8( log_stream.str().c_str() ) ); + TSTR logString = TSTR::FromUTF8(log_stream.str().c_str()); + LogToListener(_M("%3d%% - [#%d] %s: '%s' %s\n"), iterator.progress(), element->id(), e_type.data(), e_name.data(), logString.data()); Mtl *mat = ComposeMultiMaterial(material_cache, mats, ip, slot, triElement->geometry().materials(), triElement->type(), triElement->geometry().material_ids()); @@ -469,7 +469,7 @@ int IFCImp::DoImport(const TCHAR *file_name, ImpInterface *impitfc, Interface *i impitfc->AddNodeToScene(impnode_cache[i]); // Calculate the duration - unsigned int seconds = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startTime).count(); + INT64 seconds = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startTime).count(); LogToListener(_M("Import finished in %u seconds\n"), seconds); return IMPEXP_SUCCESS; @@ -487,13 +487,14 @@ BOOL IFCImp::VerifyCancel() { void IFCImp::BuildFullName( const IfcUtil::IfcBaseEntity& entity, MSTR& long_name) { - auto name = TSTR::FromUTF8(entity.get_value("Name", "").c_str()); + TSTR name = TSTR::FromUTF8(entity.get_value("Name", "").c_str()); + TSTR declName = TSTR::FromUTF8(entity.declaration().name().c_str()); - if( name.length() > 0) { - long_name.printf(_M("%s/%s [#%d]"), TSTR::FromUTF8(entity.declaration().name().c_str()), name, entity.id_); + if( _tcslen( name ) > 0) { + long_name.printf(_M("%s/%s [#%d]"), declName.data(), name.data(), entity.id_); } else { - long_name.printf(_M("%s [#%d]"), TSTR::FromUTF8(entity.declaration().name().c_str()), entity.id_); + long_name.printf(_M("%s [#%d]"), declName.data(), entity.id_); } }