From 3070d256634c8f4ff40505c068663554b02881d1 Mon Sep 17 00:00:00 2001 From: Leonardo Zide Date: Sun, 26 May 2019 11:08:47 -0700 Subject: [PATCH] Support exporting flexible parts. Fixes #157. --- common/lc_global.h | 1 + common/lc_model.cpp | 12 +-- common/lc_model.h | 7 -- common/piece.cpp | 22 +++++ common/piece.h | 1 + common/pieceinf.cpp | 1 + common/pieceinf.h | 8 ++ common/project.cpp | 199 +++++++++++++++++++++++++------------------- leocad.pro | 2 +- 9 files changed, 149 insertions(+), 104 deletions(-) diff --git a/common/lc_global.h b/common/lc_global.h index faa60edd..8abd3ac3 100644 --- a/common/lc_global.h +++ b/common/lc_global.h @@ -10,6 +10,7 @@ #include #include #include +#include #ifndef Q_FALLTHROUGH #define Q_FALLTHROUGH(); // fall through diff --git a/common/lc_model.cpp b/common/lc_model.cpp index 31cd4242..1707e96e 100644 --- a/common/lc_model.cpp +++ b/common/lc_model.cpp @@ -3124,17 +3124,7 @@ void lcModel::GetPartsListForStep(lcStep Step, int DefaultColorIndex, lcPartsLis void lcModel::GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcArray& ModelParts) const { for (lcPiece* Piece : mPieces) - { - if (!Piece->IsVisibleInSubModel()) - continue; - - int ColorIndex = Piece->mColorIndex; - - if (ColorIndex == gDefaultColor) - ColorIndex = DefaultColorIndex; - - Piece->mPieceInfo->GetModelParts(lcMul(Piece->mModelWorld, WorldMatrix), ColorIndex, ModelParts); - } + Piece->GetModelParts(WorldMatrix, DefaultColorIndex, ModelParts); } void lcModel::GetSelectionInformation(int* Flags, lcArray& Selection, lcObject** Focus) const diff --git a/common/lc_model.h b/common/lc_model.h index 476255f5..447569a3 100644 --- a/common/lc_model.h +++ b/common/lc_model.h @@ -91,13 +91,6 @@ struct lcModelHistoryEntry QString Description; }; -struct lcModelPartsEntry -{ - lcMatrix44 WorldMatrix; - PieceInfo* Info; - int ColorIndex; -}; - class lcModel { public: diff --git a/common/piece.cpp b/common/piece.cpp index 843e1d3a..f71acf86 100644 --- a/common/piece.cpp +++ b/common/piece.cpp @@ -863,6 +863,28 @@ bool lcPiece::IsVisibleInSubModel() const return (mStepHide == LC_STEP_MAX) && !(mState & LC_PIECE_HIDDEN); } +void lcPiece::GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcArray& ModelParts) const +{ + if (!IsVisibleInSubModel()) + return; + + int ColorIndex = mColorIndex; + + if (ColorIndex == gDefaultColor) + ColorIndex = DefaultColorIndex; + + if (!mMesh) + mPieceInfo->GetModelParts(lcMul(mModelWorld, WorldMatrix), ColorIndex, ModelParts); + else + { + lcModelPartsEntry& ModelPartsEntry = ModelParts.Add(); + ModelPartsEntry.WorldMatrix = WorldMatrix; + ModelPartsEntry.ColorIndex = DefaultColorIndex; + ModelPartsEntry.Info = const_cast(mPieceInfo); + ModelPartsEntry.Mesh = mMesh; + } +} + const lcBoundingBox& lcPiece::GetBoundingBox() const { if (!mMesh) diff --git a/common/piece.h b/common/piece.h index 6542f294..eb88cac7 100644 --- a/common/piece.h +++ b/common/piece.h @@ -396,6 +396,7 @@ public: const char* GetName() const override; bool IsVisible(lcStep Step) const; bool IsVisibleInSubModel() const; + void GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcArray& ModelParts) const; void Initialize(const lcMatrix44& WorldMatrix, lcStep Step); const lcBoundingBox& GetBoundingBox() const; void CompareBoundingBox(lcVector3& Min, lcVector3& Max) const; diff --git a/common/pieceinf.cpp b/common/pieceinf.cpp index 7c5f986c..4c6e3e4e 100644 --- a/common/pieceinf.cpp +++ b/common/pieceinf.cpp @@ -354,6 +354,7 @@ void PieceInfo::GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorInd ModelPartsEntry.WorldMatrix = WorldMatrix; ModelPartsEntry.ColorIndex = DefaultColorIndex; ModelPartsEntry.Info = const_cast(this); + ModelPartsEntry.Mesh = nullptr; } void PieceInfo::UpdateBoundingBox(std::vector& UpdatedModels) diff --git a/common/pieceinf.h b/common/pieceinf.h index 96cb4d13..a7f941c6 100644 --- a/common/pieceinf.h +++ b/common/pieceinf.h @@ -22,6 +22,14 @@ enum lcPieceInfoState LC_PIECEINFO_LOADED }; +struct lcModelPartsEntry +{ + lcMatrix44 WorldMatrix; + PieceInfo* Info; + lcMesh* Mesh; + int ColorIndex; +}; + class lcSynthInfo; class PieceInfo diff --git a/common/project.cpp b/common/project.cpp index 6d91ba44..5221f52e 100644 --- a/common/project.cpp +++ b/common/project.cpp @@ -615,8 +615,8 @@ void Project::GetModelParts(lcArray& ModelParts) if (mModels.IsEmpty()) return; - for (int ModelIdx = 0; ModelIdx < mModels.GetSize(); ModelIdx++) - mModels[ModelIdx]->CalculateStep(LC_STEP_MAX); + for (lcModel* Model : mModels) + Model->CalculateStep(LC_STEP_MAX); mModels[0]->GetModelParts(lcMatrix44Identity(), gDefaultColor, ModelParts); @@ -958,10 +958,9 @@ void Project::Export3DStudio(const QString& FileName) } int NumPieces = 0; - for (int PartIdx = 0; PartIdx < ModelParts.GetSize(); PartIdx++) + for (const lcModelPartsEntry& ModelPart : ModelParts) { - PieceInfo* Info = ModelParts[PartIdx].Info; - lcMesh* Mesh = Info->GetMesh(); + lcMesh* Mesh = !ModelPart.Mesh ? ModelPart.Info->GetMesh() : ModelPart.Mesh; if (!Mesh || Mesh->mIndexType == GL_UNSIGNED_INT) continue; @@ -985,7 +984,7 @@ void Project::Export3DStudio(const QString& FileName) File.WriteU16(Mesh->mNumVertices); lcVertex* Verts = (lcVertex*)Mesh->mVertexData; - const lcMatrix44& ModelWorld = ModelParts[PartIdx].WorldMatrix; + const lcMatrix44& ModelWorld = ModelPart.WorldMatrix; for (int VertexIdx = 0; VertexIdx < Mesh->mNumVertices; VertexIdx++) { @@ -1054,7 +1053,7 @@ void Project::Export3DStudio(const QString& FileName) if (Section->PrimitiveType != LC_MESH_TRIANGLES && Section->PrimitiveType != LC_MESH_TEXTURED_TRIANGLES) continue; - int MaterialIndex = Section->ColorIndex == gDefaultColor ? ModelParts[PartIdx].ColorIndex : Section->ColorIndex; + int MaterialIndex = Section->ColorIndex == gDefaultColor ? ModelPart.ColorIndex : Section->ColorIndex; File.WriteU16(0x4130); // CHK_MSH_MAT_GROUP File.WriteU32(6 + MaterialNameLength + 1 + 2 + 2 * Section->NumIndices / 3); @@ -1266,18 +1265,27 @@ void Project::ExportCOLLADA(const QString& FileName) Stream << "\r\n"; Stream << "\r\n"; - QSet AddedPieces; + std::set AddedMeshes; - for (const lcModelPartsEntry& Entry : ModelParts) + auto GetMeshID = [](const lcModelPartsEntry& ModelPart) { - PieceInfo* Info = Entry.Info; - - if (AddedPieces.contains(Info)) - continue; - AddedPieces.insert(Info); - + PieceInfo* Info = ModelPart.Info; QString ID = QString(Info->mFileName).replace('.', '_'); - lcMesh* Mesh = Info->GetMesh(); + + if (ModelPart.Mesh) + ID += "_" + QString::number((quintptr)ModelPart.Mesh, 16); + + return ID; + }; + + for (const lcModelPartsEntry& ModelPart : ModelParts) + { + lcMesh* Mesh = !ModelPart.Mesh ? ModelPart.Info->GetMesh() : ModelPart.Mesh; + + if (!AddedMeshes.insert(Mesh).second) + continue; + + QString ID = GetMeshID(ModelPart); if (!Mesh) Mesh = gPlaceholderMesh; @@ -1387,15 +1395,14 @@ void Project::ExportCOLLADA(const QString& FileName) Stream << "\r\n"; Stream << "\t\r\n"; - for (const lcModelPartsEntry& Entry : ModelParts) + for (const lcModelPartsEntry& ModelPart : ModelParts) { - PieceInfo* Info = Entry.Info; - QString ID = QString(Info->mFileName).replace('.', '_'); + QString ID = GetMeshID(ModelPart); Stream << "\t\t\r\n"; Stream << "\t\t\t\r\n"; - const lcMatrix44& Matrix = Entry.WorldMatrix; + const lcMatrix44& Matrix = ModelPart.WorldMatrix; Stream << QString("\t\t\t\t%1 %2 %3 %4\r\n").arg(QString::number(Matrix[0][0]), QString::number(Matrix[1][0]), QString::number(Matrix[2][0]), QString::number(Matrix[3][0])); Stream << QString("\t\t\t\t%1 %2 %3 %4\r\n").arg(QString::number(Matrix[0][1]), QString::number(Matrix[1][1]), QString::number(Matrix[2][1]), QString::number(Matrix[3][1])); Stream << QString("\t\t\t\t%1 %2 %3 %4\r\n").arg(QString::number(Matrix[0][2]), QString::number(Matrix[1][2]), QString::number(Matrix[2][2]), QString::number(Matrix[3][2])); @@ -1406,7 +1413,7 @@ void Project::ExportCOLLADA(const QString& FileName) Stream << "\t\t\t\t\r\n"; Stream << "\t\t\t\t\t\r\n"; - lcMesh* Mesh = Info->GetMesh(); + lcMesh* Mesh = !ModelPart.Mesh ? ModelPart.Info->GetMesh() : ModelPart.Mesh; if (!Mesh) Mesh = gPlaceholderMesh; @@ -1421,7 +1428,7 @@ void Project::ExportCOLLADA(const QString& FileName) const char* SourceColorName = gColorList[Section->ColorIndex].SafeName; const char* TargetColorName; if (Section->ColorIndex == gDefaultColor) - TargetColorName = gColorList[Entry.ColorIndex].SafeName; + TargetColorName = gColorList[ModelPart.ColorIndex].SafeName; else TargetColorName = gColorList[Section->ColorIndex].SafeName; @@ -2155,35 +2162,34 @@ bool Project::ExportPOVRay(const QString& FileName) } } + std::set AddedMeshes; + if (!LGEOPath.isEmpty()) { POVFile.WriteLine("#include \"lg_defs.inc\"\n#include \"lg_color.inc\"\n\n"); - for (int PartIdx = 0; PartIdx < ModelParts.GetSize(); PartIdx++) + for (const lcModelPartsEntry& ModelPart : ModelParts) { - PieceInfo* Info = ModelParts[PartIdx].Info; + if (ModelPart.Mesh) + continue; - for (int CheckIdx = 0; CheckIdx < ModelParts.GetSize(); CheckIdx++) + auto Search = PieceTable.find(ModelPart.Info); + if (Search == PieceTable.end()) + continue; + + lcMesh* Mesh = ModelPart.Info->GetMesh(); + + if (!Mesh) + continue; + + if (!AddedMeshes.insert(Mesh).second) + continue; + + const std::pair& Entry = Search->second; + if (Entry.first[0]) { - if (ModelParts[CheckIdx].Info != Info) - continue; - - if (CheckIdx != PartIdx) - break; - - auto Search = PieceTable.find(Info); - - if (Search != PieceTable.end()) - { - const std::pair& Entry = Search->second; - if (Entry.first[0]) - { - sprintf(Line, "#include \"%s.inc\"\n", Entry.first); - POVFile.WriteLine(Line); - } - } - - break; + sprintf(Line, "#include \"%s.inc\"\n", Entry.first); + POVFile.WriteLine(Line); } } @@ -2218,25 +2224,40 @@ bool Project::ExportPOVRay(const QString& FileName) for (int ColorIdx = 0; ColorIdx < NumColors; ColorIdx++) ColorTablePointer[ColorIdx] = ColorTable[ColorIdx].data(); - for (int PartIdx = 0; PartIdx < ModelParts.GetSize(); PartIdx++) + auto GetMeshName = [](const lcModelPartsEntry& ModelPart, char* Name) { - PieceInfo* Info = ModelParts[PartIdx].Info; - lcMesh* Mesh = Info->GetMesh(); - std::pair& Entry = PieceTable[Info]; + strcpy(Name, ModelPart.Info->mFileName); - if (!Mesh || Entry.first[0]) + for (char* c = Name; *c; c++) + if (*c == '-' || *c == '.') + *c = '_'; + + if (ModelPart.Mesh) + { + char Suffix[32]; + sprintf(Suffix, "_%p", ModelPart.Mesh); + strcat(Name, Suffix); + } + }; + + for (const lcModelPartsEntry& ModelPart : ModelParts) + { + lcMesh* Mesh = !ModelPart.Mesh ? ModelPart.Info->GetMesh() : ModelPart.Mesh; + + if (!AddedMeshes.insert(Mesh).second) + continue; + + if (!Mesh) continue; char Name[LC_PIECE_NAME_LEN]; - char* Ptr; + GetMeshName(ModelPart, Name); - strcpy(Name, Info->mFileName); - while ((Ptr = strchr(Name, '-'))) - *Ptr = '_'; - while ((Ptr = strchr(Name, '.'))) - *Ptr = '_'; - - sprintf(Entry.first, "lc_%s", Name); + if (!ModelPart.Mesh) + { + std::pair& Entry = PieceTable[ModelPart.Info]; + sprintf(Entry.first, "lc_%s", Name); + } Mesh->ExportPOVRay(POVFile, Name, &ColorTablePointer[0]); @@ -2287,32 +2308,41 @@ bool Project::ExportPOVRay(const QString& FileName) sprintf(Line, "light_source{ <%f, %f, %f>\n color rgb 0.5\n area_light 200, 200, 10, 10\n jitter\n}\n\n", 2.0f * Radius + Center.x, 0.0f * Radius + Center.y, -2.0f * Radius + Center.z); POVFile.WriteLine(Line); - for (int PartIdx = 0; PartIdx < ModelParts.GetSize(); PartIdx++) + for (const lcModelPartsEntry& ModelPart : ModelParts) { - PieceInfo* Info = ModelParts[PartIdx].Info; - std::pair& Entry = PieceTable[Info]; - int Color; - - Color = ModelParts[PartIdx].ColorIndex; + int Color = ModelPart.ColorIndex; const char* Suffix = lcIsColorTranslucent(Color) ? "_clear" : ""; + const float* f = ModelPart.WorldMatrix; - const float* f = ModelParts[PartIdx].WorldMatrix; - - if (Entry.second & LGEO_PIECE_SLOPE) + if (!ModelPart.Mesh) { - sprintf(Line, "merge {\n object {\n %s%s\n texture { %s }\n }\n" - " object {\n %s_slope\n texture { %s normal { bumps 0.3 scale 0.02 } }\n }\n" - " matrix <%.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f>\n}\n", - Entry.first, Suffix, ColorTable[Color].data(), Entry.first, ColorTable[Color].data(), - -f[5], -f[4], -f[6], -f[1], -f[0], -f[2], f[9], f[8], f[10], f[13] / 25.0f, f[12] / 25.0f, f[14] / 25.0f); + std::pair& Entry = PieceTable[ModelPart.Info]; + + if (Entry.second & LGEO_PIECE_SLOPE) + { + sprintf(Line, "merge {\n object {\n %s%s\n texture { %s }\n }\n" + " object {\n %s_slope\n texture { %s normal { bumps 0.3 scale 0.02 } }\n }\n" + " matrix <%.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f>\n}\n", + Entry.first, Suffix, ColorTable[Color].data(), Entry.first, ColorTable[Color].data(), + -f[5], -f[4], -f[6], -f[1], -f[0], -f[2], f[9], f[8], f[10], f[13] / 25.0f, f[12] / 25.0f, f[14] / 25.0f); + } + else + { + if (!ModelPart.Info || !ModelPart.Info->GetMesh()) + continue; + + sprintf(Line, "object {\n %s%s\n texture { %s }\n matrix <%.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f>\n}\n", + Entry.first, Suffix, ColorTable[Color].data(), -f[5], -f[4], -f[6], -f[1], -f[0], -f[2], f[9], f[8], f[10], f[13] / 25.0f, f[12] / 25.0f, f[14] / 25.0f); + + } } else { - if (!Info || !Info->GetMesh()) - continue; + char Name[LC_PIECE_NAME_LEN]; + GetMeshName(ModelPart, Name); - sprintf(Line, "object {\n %s%s\n texture { %s }\n matrix <%.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f>\n}\n", - Entry.first, Suffix, ColorTable[Color].data(), -f[5], -f[4], -f[6], -f[1], -f[0], -f[2], f[9], f[8], f[10], f[13] / 25.0f, f[12] / 25.0f, f[14] / 25.0f); + sprintf(Line, "object {\n lc_%s%s\n texture { %s }\n matrix <%.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f>\n}\n", + Name, Suffix, ColorTable[Color].data(), -f[5], -f[4], -f[6], -f[1], -f[0], -f[2], f[9], f[8], f[10], f[13] / 25.0f, f[12] / 25.0f, f[14] / 25.0f); } POVFile.WriteLine(Line); @@ -2377,14 +2407,14 @@ void Project::ExportWavefront(const QString& FileName) MaterialFile.WriteLine(Line); } - for (int PartIdx = 0; PartIdx < ModelParts.GetSize(); PartIdx++) + for (const lcModelPartsEntry& ModelPart : ModelParts) { - lcMesh* Mesh = ModelParts[PartIdx].Info->GetMesh(); + lcMesh* Mesh = !ModelPart.Mesh ? ModelPart.Info->GetMesh() : ModelPart.Mesh; if (!Mesh) continue; - const lcMatrix44& ModelWorld = ModelParts[PartIdx].WorldMatrix; + const lcMatrix44& ModelWorld = ModelPart.WorldMatrix; lcVertex* Verts = (lcVertex*)Mesh->mVertexData; for (int VertexIdx = 0; VertexIdx < Mesh->mNumVertices; VertexIdx++) @@ -2397,14 +2427,14 @@ void Project::ExportWavefront(const QString& FileName) OBJFile.WriteLine("#\n\n"); } - for (int PartIdx = 0; PartIdx < ModelParts.GetSize(); PartIdx++) + for (const lcModelPartsEntry& ModelPart : ModelParts) { - lcMesh* Mesh = ModelParts[PartIdx].Info->GetMesh(); + lcMesh* Mesh = !ModelPart.Mesh ? ModelPart.Info->GetMesh() : ModelPart.Mesh; if (!Mesh) continue; - const lcMatrix44& ModelWorld = ModelParts[PartIdx].WorldMatrix; + const lcMatrix44& ModelWorld = ModelPart.WorldMatrix; lcVertex* Verts = (lcVertex*)Mesh->mVertexData; for (int VertexIdx = 0; VertexIdx < Mesh->mNumVertices; VertexIdx++) @@ -2419,16 +2449,15 @@ void Project::ExportWavefront(const QString& FileName) for (int PartIdx = 0; PartIdx < ModelParts.GetSize(); PartIdx++) { - PieceInfo* Info = ModelParts[PartIdx].Info; - sprintf(Line, "g Piece%.3d\n", PartIdx); OBJFile.WriteLine(Line); - lcMesh* Mesh = Info->GetMesh(); + const lcModelPartsEntry& ModelPart = ModelParts[PartIdx]; + lcMesh* Mesh = !ModelPart.Mesh ? ModelPart.Info->GetMesh() : ModelPart.Mesh; if (Mesh) { - Mesh->ExportWavefrontIndices(OBJFile, ModelParts[PartIdx].ColorIndex, vert); + Mesh->ExportWavefrontIndices(OBJFile, ModelPart.ColorIndex, vert); vert += Mesh->mNumVertices; } } diff --git a/leocad.pro b/leocad.pro index aa010039..572201a8 100644 --- a/leocad.pro +++ b/leocad.pro @@ -14,7 +14,7 @@ equals(QT_MAJOR_VERSION, 5) { } INCLUDEPATH += qt common -CONFIG += precompile_header incremental c++11 +CONFIG += precompile_header incremental c++11 force_debug_info win32 { RC_FILE = qt/leocad.rc