mirror of
https://github.com/leozide/leocad.git
synced 2026-10-27 06:20:55 +00:00
Move the library directory and shared vertex/index buffer handles into the protected source and rendering groups. Expose one GetBuffers accessor returning const references to both buffers, and use structured binding in BindMesh while preserving GL binding and uncached-mesh fallback behavior. Add GetLibraryFilePath for mapping-file lookups and update the LXF and BrickLink callers. Keep file opening and bundled-resource fallback in those callers so the library only resolves the path and exposes no mutable directory state. Validation: warning-free macOS Qt 6.10 Debug build, all 45 offscreen lifecycle checks and diff whitespace checks pass. No remaining external field accesses for the protected directory or buffers. GPU rendering was not tested.
203 lines
7.0 KiB
C++
203 lines
7.0 KiB
C++
#include "lc_global.h"
|
|
#include "lc_lxf.h"
|
|
#include "lc_library.h"
|
|
#include "lc_application.h"
|
|
#include "lc_mainwindow.h"
|
|
#include "piece.h"
|
|
#include "lc_file.h"
|
|
#include <QDomDocument>
|
|
|
|
static bool lcLoadLDrawXML(std::map<int, int>& MaterialTable, std::map<int, std::string>& BrickTable, std::map<std::string, std::pair<lcVector3, lcVector4>>& TransformTable)
|
|
{
|
|
QFile File(lcGetPiecesLibrary()->GetLibraryFilePath(QLatin1String("ldraw.xml")));
|
|
QByteArray Data;
|
|
|
|
if (File.open(QIODevice::ReadOnly))
|
|
Data = File.readAll();
|
|
else
|
|
{
|
|
QFile DefaultFile(":/resources/ldraw.xml");
|
|
|
|
if (DefaultFile.open(QIODevice::ReadOnly))
|
|
Data = DefaultFile.readAll();
|
|
}
|
|
|
|
if (Data.isEmpty())
|
|
return false;
|
|
|
|
QDomDocument Document;
|
|
Document.setContent(QString::fromUtf8(Data));
|
|
|
|
QDomElement Root = Document.documentElement();
|
|
if (Root.tagName() != QLatin1String("LDrawMapping"))
|
|
return false;
|
|
|
|
for (QDomNode Node = Root.firstChild(); !Node.isNull(); Node = Node.nextSibling())
|
|
{
|
|
QDomElement Element = Node.toElement();
|
|
QString ElementName = Element.tagName();
|
|
|
|
if (ElementName == QLatin1String("Material"))
|
|
{
|
|
int LDrawColor = Element.attribute(QLatin1String("ldraw")).toInt();
|
|
int LegoColor = Element.attribute(QLatin1String("lego")).toInt();
|
|
|
|
MaterialTable[LegoColor] = LDrawColor;
|
|
}
|
|
else if (ElementName == QLatin1String("Brick"))
|
|
{
|
|
QString LDrawID = Element.attribute(QLatin1String("ldraw"));
|
|
int LegoID = Element.attribute(QLatin1String("lego")).toInt();
|
|
|
|
BrickTable.insert(std::make_pair(LegoID, LDrawID.toStdString()));
|
|
}
|
|
else if (ElementName == QLatin1String("Transformation"))
|
|
{
|
|
QString LDrawID = Element.attribute(QLatin1String("ldraw"));
|
|
|
|
lcVector3 Translation;
|
|
lcVector4 AxisAngle;
|
|
|
|
Translation[0] = Element.attribute(QLatin1String("tx")).toFloat();
|
|
Translation[1] = Element.attribute(QLatin1String("ty")).toFloat();
|
|
Translation[2] = Element.attribute(QLatin1String("tz")).toFloat();
|
|
AxisAngle[0] = Element.attribute(QLatin1String("ax")).toFloat();
|
|
AxisAngle[1] = Element.attribute(QLatin1String("ay")).toFloat();
|
|
AxisAngle[2] = Element.attribute(QLatin1String("az")).toFloat();
|
|
AxisAngle[3] = Element.attribute(QLatin1String("angle")).toFloat();
|
|
|
|
TransformTable.insert(std::make_pair(LDrawID.toStdString(), std::make_pair(Translation, AxisAngle)));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool lcImportLXFMLFile(const QString& FileData, Project* Project, std::vector<lcPiece*>& Pieces, std::vector<std::vector<lcPiece*>>& Groups)
|
|
{
|
|
std::map<int, int> MaterialTable;
|
|
std::map<int, std::string> BrickTable;
|
|
std::map<std::string, std::pair<lcVector3, lcVector4>> TransformTable;
|
|
|
|
if (!lcLoadLDrawXML(MaterialTable, BrickTable, TransformTable))
|
|
return false;
|
|
|
|
QDomDocument Document;
|
|
Document.setContent(FileData);
|
|
|
|
QDomElement Root = Document.documentElement();
|
|
if (Root.tagName() != QLatin1String("LXFML"))
|
|
return false;
|
|
|
|
for (QDomNode SectionNode = Root.firstChild(); !SectionNode.isNull(); SectionNode = SectionNode.nextSibling())
|
|
{
|
|
QDomElement SectionElement = SectionNode.toElement();
|
|
if (SectionElement.tagName() != QLatin1String("Bricks"))
|
|
continue;
|
|
|
|
for (QDomNode BrickNode = SectionElement.firstChild(); !BrickNode.isNull(); BrickNode = BrickNode.nextSibling())
|
|
{
|
|
QDomElement BrickElement = BrickNode.toElement();
|
|
if (BrickElement.tagName() != QLatin1String("Brick"))
|
|
continue;
|
|
|
|
int NumBrickPieces = 0;
|
|
|
|
for (QDomNode PartNode = BrickElement.firstChild(); !PartNode.isNull(); PartNode = PartNode.nextSibling())
|
|
{
|
|
QDomElement PartElement = PartNode.toElement();
|
|
if (PartElement.tagName() != QLatin1String("Part"))
|
|
continue;
|
|
|
|
bool BoneFound = false;
|
|
lcMatrix44 WorldMatrix;
|
|
|
|
for (QDomNode BoneNode = PartElement.firstChild(); !BoneNode.isNull(); BoneNode = BoneNode.nextSibling())
|
|
{
|
|
QDomElement BoneElement = BoneNode.toElement();
|
|
if (BoneElement.tagName() != QLatin1String("Bone"))
|
|
continue;
|
|
|
|
QString BoneTransform = BoneElement.attribute(QLatin1String("transformation"));
|
|
QStringList BoneElements = BoneTransform.split(',');
|
|
|
|
if (BoneElements.size() != 12)
|
|
continue;
|
|
|
|
WorldMatrix[0][0] = BoneElements[0].toFloat();
|
|
WorldMatrix[0][1] = BoneElements[1].toFloat();
|
|
WorldMatrix[0][2] = BoneElements[2].toFloat();
|
|
WorldMatrix[0][3] = 0.0f;
|
|
WorldMatrix[1][0] = BoneElements[3].toFloat();
|
|
WorldMatrix[1][1] = BoneElements[4].toFloat();
|
|
WorldMatrix[1][2] = BoneElements[5].toFloat();
|
|
WorldMatrix[1][3] = 0.0f;
|
|
WorldMatrix[2][0] = BoneElements[6].toFloat();
|
|
WorldMatrix[2][1] = BoneElements[7].toFloat();
|
|
WorldMatrix[2][2] = BoneElements[8].toFloat();
|
|
WorldMatrix[2][3] = 0.0f;
|
|
WorldMatrix[3][0] = BoneElements[9].toFloat();
|
|
WorldMatrix[3][1] = BoneElements[10].toFloat();
|
|
WorldMatrix[3][2] = BoneElements[11].toFloat();
|
|
WorldMatrix[3][3] = 1.0f;
|
|
|
|
BoneFound = true;
|
|
break;
|
|
}
|
|
|
|
if (!BoneFound)
|
|
continue;
|
|
|
|
QString LegoID = PartElement.attribute(QLatin1String("designID"));
|
|
int Material = PartElement.attribute(QLatin1String("materials")).split(',').first().toInt();
|
|
|
|
lcPieceDataRef PieceData;
|
|
const auto BrickIt = BrickTable.find(LegoID.toInt());
|
|
|
|
if (BrickIt != BrickTable.end())
|
|
PieceData = lcGetPiecesLibrary()->AcquirePieceData(BrickIt->second.c_str(), Project, true, false);
|
|
else
|
|
PieceData = lcGetPiecesLibrary()->AcquirePieceData(LegoID.toLatin1() + ".dat", Project, true, false);
|
|
|
|
const auto ColorIt = MaterialTable.find(Material);
|
|
int ColorCode = 16;
|
|
|
|
if (ColorIt != MaterialTable.end())
|
|
ColorCode = ColorIt->second;
|
|
|
|
const auto TransformIt = TransformTable.find(BrickIt != BrickTable.end() ? BrickIt->second : (LegoID.toStdString() + ".dat"));
|
|
if (TransformIt != TransformTable.end())
|
|
{
|
|
const lcVector4& AxisAngle = TransformIt->second.second;
|
|
const lcVector3& TransformTranslation = TransformIt->second.first;
|
|
|
|
lcMatrix44 Transform = lcMatrix44FromAxisAngle(lcVector3(AxisAngle[0], AxisAngle[1], AxisAngle[2]), -AxisAngle[3]);
|
|
Transform.SetTranslation(lcMul30(-TransformTranslation, Transform));
|
|
|
|
WorldMatrix = lcMul(Transform, WorldMatrix);
|
|
}
|
|
|
|
WorldMatrix = lcMatrix44(lcVector4(WorldMatrix[0][0], -WorldMatrix[0][1], -WorldMatrix[0][2], 0.0f), lcVector4(-WorldMatrix[1][0], WorldMatrix[1][1], WorldMatrix[1][2], 0.0f),
|
|
lcVector4(-WorldMatrix[2][0], WorldMatrix[2][1], WorldMatrix[2][2], 0.0f), lcVector4(WorldMatrix[3][0] * 25.0f, -WorldMatrix[3][1] * 25.0f, -WorldMatrix[3][2] * 25.0f, 1.0f));
|
|
|
|
lcPiece* Piece = new lcPiece(nullptr);
|
|
Piece->SetPieceData(std::move(PieceData), QString(), false, true);
|
|
Piece->Initialize(lcMatrix44LDrawToLeoCAD(WorldMatrix), 1);
|
|
Piece->SetColorCode(ColorCode);
|
|
Pieces.push_back(Piece);
|
|
NumBrickPieces++;
|
|
}
|
|
|
|
if (NumBrickPieces > 1)
|
|
{
|
|
std::vector<lcPiece*> Group;
|
|
for (size_t PieceIdx = Pieces.size() - NumBrickPieces; PieceIdx < Pieces.size(); PieceIdx++)
|
|
Group.push_back(Pieces[PieceIdx]);
|
|
Groups.push_back(Group);
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|