1 #include "lc_global.h"
2 #include "lc_lxf.h"
3 #include "lc_library.h"
4 #include "lc_application.h"
5 #include "lc_mainwindow.h"
6 #include "piece.h"
7 #include "lc_file.h"
8 #include <QDomDocument>
9 
lcLoadLDrawXML(std::map<int,int> & MaterialTable,std::map<int,std::string> & BrickTable,std::map<std::string,std::pair<lcVector3,lcVector4>> & TransformTable)10 static bool lcLoadLDrawXML(std::map<int, int>& MaterialTable, std::map<int, std::string>& BrickTable, std::map<std::string, std::pair<lcVector3, lcVector4>>& TransformTable)
11 {
12 	QFile File(lcGetPiecesLibrary()->mLibraryDir.absoluteFilePath(QLatin1String("ldraw.xml")));
13 	QByteArray Data;
14 
15 	if (File.open(QIODevice::ReadOnly))
16 		Data = File.readAll();
17 	else
18 	{
19 		QFile DefaultFile(":/resources/ldraw.xml");
20 
21 		if (DefaultFile.open(QIODevice::ReadOnly))
22 			Data = DefaultFile.readAll();
23 	}
24 
25 	if (Data.isEmpty())
26 		return false;
27 
28 	QDomDocument Document;
29 	Document.setContent(QString::fromUtf8(Data));
30 
31 	QDomElement Root = Document.documentElement();
32 	if (Root.tagName() != QLatin1String("LDrawMapping"))
33 		return false;
34 
35 	for (QDomNode Node = Root.firstChild(); !Node.isNull(); Node = Node.nextSibling())
36 	{
37 		QDomElement Element = Node.toElement();
38 		QString ElementName = Element.tagName();
39 
40 		if (ElementName == QLatin1String("Material"))
41 		{
42 			int LDrawColor = Element.attribute(QLatin1String("ldraw")).toInt();
43 			int LegoColor = Element.attribute(QLatin1String("lego")).toInt();
44 
45 			MaterialTable[LegoColor] = LDrawColor;
46 		}
47 		else if (ElementName == QLatin1String("Brick"))
48 		{
49 			QString LDrawID = Element.attribute(QLatin1String("ldraw"));
50 			int LegoID = Element.attribute(QLatin1String("lego")).toInt();
51 
52 			BrickTable.insert(std::make_pair(LegoID, LDrawID.toStdString()));
53 		}
54 		else if (ElementName == QLatin1String("Transformation"))
55 		{
56 			QString LDrawID = Element.attribute(QLatin1String("ldraw"));
57 
58 			lcVector3 Translation;
59 			lcVector4 AxisAngle;
60 
61 			Translation[0] = Element.attribute(QLatin1String("tx")).toFloat();
62 			Translation[1] = Element.attribute(QLatin1String("ty")).toFloat();
63 			Translation[2] = Element.attribute(QLatin1String("tz")).toFloat();
64 			AxisAngle[0] = Element.attribute(QLatin1String("ax")).toFloat();
65 			AxisAngle[1] = Element.attribute(QLatin1String("ay")).toFloat();
66 			AxisAngle[2] = Element.attribute(QLatin1String("az")).toFloat();
67 			AxisAngle[3] = Element.attribute(QLatin1String("angle")).toFloat();
68 
69 			TransformTable.insert(std::make_pair(LDrawID.toStdString(), std::make_pair(Translation, AxisAngle)));
70 		}
71 	}
72 
73 	return true;
74 }
75 
lcImportLXFMLFile(const QString & FileData,std::vector<lcPiece * > & Pieces,std::vector<std::vector<lcPiece * >> & Groups)76 bool lcImportLXFMLFile(const QString& FileData, std::vector<lcPiece*>& Pieces, std::vector<std::vector<lcPiece*>>& Groups)
77 {
78 	std::map<int, int> MaterialTable;
79 	std::map<int, std::string> BrickTable;
80 	std::map<std::string, std::pair<lcVector3, lcVector4>> TransformTable;
81 
82 	if (!lcLoadLDrawXML(MaterialTable, BrickTable, TransformTable))
83 		return false;
84 
85 	QDomDocument Document;
86 	Document.setContent(FileData);
87 
88 	QDomElement Root = Document.documentElement();
89 	if (Root.tagName() != QLatin1String("LXFML"))
90 		return false;
91 
92 	for (QDomNode SectionNode = Root.firstChild(); !SectionNode.isNull(); SectionNode = SectionNode.nextSibling())
93 	{
94 		QDomElement SectionElement = SectionNode.toElement();
95 		if (SectionElement.tagName() != QLatin1String("Bricks"))
96 			continue;
97 
98 		for (QDomNode BrickNode = SectionElement.firstChild(); !BrickNode.isNull(); BrickNode = BrickNode.nextSibling())
99 		{
100 			QDomElement BrickElement = BrickNode.toElement();
101 			if (BrickElement.tagName() != QLatin1String("Brick"))
102 				continue;
103 
104 			int NumBrickPieces = 0;
105 
106 			for (QDomNode PartNode = BrickElement.firstChild(); !PartNode.isNull(); PartNode = PartNode.nextSibling())
107 			{
108 				QDomElement PartElement = PartNode.toElement();
109 				if (PartElement.tagName() != QLatin1String("Part"))
110 					continue;
111 
112 				bool BoneFound = false;
113 				lcMatrix44 WorldMatrix;
114 
115 				for (QDomNode BoneNode = PartElement.firstChild(); !BoneNode.isNull(); BoneNode = BoneNode.nextSibling())
116 				{
117 					QDomElement BoneElement = BoneNode.toElement();
118 					if (BoneElement.tagName() != QLatin1String("Bone"))
119 						continue;
120 
121 					QString BoneTransform = BoneElement.attribute(QLatin1String("transformation"));
122 					QStringList BoneElements = BoneTransform.split(',');
123 
124 					if (BoneElements.size() != 12)
125 						continue;
126 
127 					WorldMatrix[0][0] = BoneElements[0].toFloat();
128 					WorldMatrix[0][1] = BoneElements[1].toFloat();
129 					WorldMatrix[0][2] = BoneElements[2].toFloat();
130 					WorldMatrix[0][3] = 0.0f;
131 					WorldMatrix[1][0] = BoneElements[3].toFloat();
132 					WorldMatrix[1][1] = BoneElements[4].toFloat();
133 					WorldMatrix[1][2] = BoneElements[5].toFloat();
134 					WorldMatrix[1][3] = 0.0f;
135 					WorldMatrix[2][0] = BoneElements[6].toFloat();
136 					WorldMatrix[2][1] = BoneElements[7].toFloat();
137 					WorldMatrix[2][2] = BoneElements[8].toFloat();
138 					WorldMatrix[3][3] = 0.0f;
139 					WorldMatrix[3][0] = BoneElements[9].toFloat();
140 					WorldMatrix[3][1] = BoneElements[10].toFloat();
141 					WorldMatrix[3][2] = BoneElements[11].toFloat();
142 					WorldMatrix[3][3] = 1.0f;
143 
144 					BoneFound = true;
145 					break;
146 				}
147 
148 				if (!BoneFound)
149 					continue;
150 
151 				QString LegoID = PartElement.attribute(QLatin1String("designID"));
152 				int Material = PartElement.attribute(QLatin1String("materials")).split(',').first().toInt();
153 
154 				PieceInfo* Info = nullptr;
155 				const auto BrickIt = BrickTable.find(LegoID.toInt());
156 				if (BrickIt != BrickTable.end())
157 					Info = lcGetPiecesLibrary()->FindPiece(BrickIt->second.c_str(), nullptr, true, false);
158 				else
159 					Info = lcGetPiecesLibrary()->FindPiece(LegoID.toLatin1() + ".dat", nullptr, true, false);
160 
161 				const auto ColorIt = MaterialTable.find(Material);
162 				int ColorCode = 16;
163 				if (ColorIt != MaterialTable.end())
164 					ColorCode = ColorIt->second;
165 
166 				const auto TransformIt = TransformTable.find(BrickIt != BrickTable.end() ? BrickIt->second : (LegoID.toStdString() + ".dat"));
167 				if (TransformIt != TransformTable.end())
168 				{
169 					const lcVector4& AxisAngle = TransformIt->second.second;
170 					const lcVector3& TransformTranslation = TransformIt->second.first;
171 
172 					lcMatrix44 Transform = lcMatrix44FromAxisAngle(lcVector3(AxisAngle[0], AxisAngle[1], AxisAngle[2]), -AxisAngle[3]);
173 					Transform.SetTranslation(lcMul30(-TransformTranslation, Transform));
174 
175 					WorldMatrix = lcMul(Transform, WorldMatrix);
176 				}
177 
178 				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),
179 										 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));
180 
181 				lcPiece* Piece = new lcPiece(nullptr);
182 				Piece->SetPieceInfo(Info, QString(), false);
183 				Piece->Initialize(lcMatrix44LDrawToLeoCAD(WorldMatrix), 1);
184 				Piece->SetColorCode(ColorCode);
185 				Pieces.push_back(Piece);
186 				NumBrickPieces++;
187 			}
188 
189 			if (NumBrickPieces > 1)
190 			{
191 				std::vector<lcPiece*> Group;
192 				for (size_t PieceIdx = Pieces.size() - NumBrickPieces; PieceIdx < Pieces.size(); PieceIdx++)
193 					Group.push_back(Pieces[PieceIdx]);
194 				Groups.push_back(Group);
195 			}
196 		}
197 	}
198 
199 	return true;
200 }
201