mirror of
https://github.com/leozide/leocad
synced 2025-01-28 19:58:12 +01:00
Added LDD importer. Closes #29.
This commit is contained in:
parent
4ef698ddf4
commit
f0eb8bde96
13 changed files with 18861 additions and 0 deletions
|
@ -45,6 +45,13 @@ lcCommand gCommands[LC_NUM_COMMANDS] =
|
|||
QT_TRANSLATE_NOOP("Status", "Save a picture of the current view"),
|
||||
QT_TRANSLATE_NOOP("Shortcut", "")
|
||||
},
|
||||
// LC_FILE_IMPORT_LDD
|
||||
{
|
||||
QT_TRANSLATE_NOOP("Action", "File.Import.LDD"),
|
||||
QT_TRANSLATE_NOOP("Menu", "&LEGO Digital Designer..."),
|
||||
QT_TRANSLATE_NOOP("Status", "Import a file in LEGO Digital Designer LXF format"),
|
||||
QT_TRANSLATE_NOOP("Shortcut", "")
|
||||
},
|
||||
// LC_FILE_EXPORT_3DS
|
||||
{
|
||||
QT_TRANSLATE_NOOP("Action", "File.Export.3DS"),
|
||||
|
|
|
@ -9,6 +9,7 @@ enum lcCommandId
|
|||
LC_FILE_SAVE,
|
||||
LC_FILE_SAVEAS,
|
||||
LC_FILE_SAVE_IMAGE,
|
||||
LC_FILE_IMPORT_LDD,
|
||||
LC_FILE_EXPORT_3DS,
|
||||
LC_FILE_EXPORT_HTML,
|
||||
LC_FILE_EXPORT_BRICKLINK,
|
||||
|
|
564
common/lc_lxf.cpp
Normal file
564
common/lc_lxf.cpp
Normal file
|
@ -0,0 +1,564 @@
|
|||
#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"
|
||||
|
||||
// Based on https://gitlab.com/sylvainls/lxf2ldr
|
||||
|
||||
#define LC_READ_XML_INT(attribute, variable) \
|
||||
variable = Reader.attributes().value(attribute).toInt(&Ok); \
|
||||
if (!Ok) \
|
||||
return false;
|
||||
#define LC_READ_XML_FLOAT(attribute, variable) \
|
||||
variable = Reader.attributes().value(attribute).toFloat(&Ok); \
|
||||
if (!Ok) \
|
||||
return false;
|
||||
|
||||
inline QMatrix4x4 lcLDDRotationMatrix(double ax, double ay, double az, double Angle)
|
||||
{
|
||||
QMatrix4x4 Matrix;
|
||||
Matrix.rotate(Angle, ax, ay, az);
|
||||
return Matrix;
|
||||
}
|
||||
|
||||
struct lcLDDTransformation
|
||||
{
|
||||
QVector3D Translation;
|
||||
QMatrix4x4 Rotation;
|
||||
|
||||
lcLDDTransformation(const QVector3D& vtrans, const QMatrix4x4& vrot)
|
||||
: Translation(vtrans), Rotation(vrot)
|
||||
{
|
||||
}
|
||||
|
||||
lcLDDTransformation()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct lcLDDSubstitute
|
||||
{
|
||||
QString LDrawFile;
|
||||
const lcLDDTransformation* Transformation;
|
||||
|
||||
lcLDDSubstitute()
|
||||
: Transformation(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
lcLDDSubstitute(const QString& vdatfile, const lcLDDTransformation *const vtransformation)
|
||||
: LDrawFile(vdatfile), Transformation(vtransformation)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct lcLDDSimpleSubstitute
|
||||
{
|
||||
QString LDrawFile;
|
||||
bool Overwrite;
|
||||
|
||||
lcLDDSimpleSubstitute()
|
||||
: Overwrite(false)
|
||||
{
|
||||
}
|
||||
|
||||
lcLDDSimpleSubstitute(const QString& vdatfile, bool voverwrite)
|
||||
: LDrawFile(vdatfile), Overwrite(voverwrite)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef QMap<int, lcLDDSimpleSubstitute> lcLDDColorMap;
|
||||
typedef QMap<QString, lcLDDSubstitute> lcLDDDecorationMap;
|
||||
|
||||
struct DecorMatch
|
||||
{
|
||||
int UseColor;
|
||||
QList<lcLDDColorMap> Colors;
|
||||
lcLDDDecorationMap Decorations;
|
||||
|
||||
DecorMatch()
|
||||
: UseColor(0)
|
||||
{
|
||||
}
|
||||
|
||||
DecorMatch(int vusecolor, const QList<lcLDDColorMap>& vcolors, const lcLDDDecorationMap& vdecorations)
|
||||
: UseColor(vusecolor), Colors(vcolors), Decorations(vdecorations)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct lcLDDAssembly
|
||||
{
|
||||
int id;
|
||||
QStringList Parts;
|
||||
|
||||
lcLDDAssembly()
|
||||
{
|
||||
}
|
||||
|
||||
lcLDDAssembly(int vid, const QStringList vparts)
|
||||
: id(vid), Parts(vparts)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static bool lcLDDReadLDrawXML(QMap<int, int>& MaterialTable, QMap<int, QString>& BrickTable, QMap<QString, lcLDDTransformation>& TransformationTable, QMap<int, lcLDDAssembly>& AssemblyTable)
|
||||
{
|
||||
QString DiskFileName(lcGetPiecesLibrary()->mLibraryDir.absoluteFilePath(QLatin1String("ldraw.xml")));
|
||||
|
||||
QXmlStreamReader Reader;
|
||||
QFile DiskFile(DiskFileName);
|
||||
|
||||
if (DiskFile.open(QFile::ReadOnly | QFile::Text))
|
||||
Reader.setDevice(&DiskFile);
|
||||
else
|
||||
{
|
||||
QResource Resource(QLatin1String(":/resources/ldraw.xml"));
|
||||
|
||||
if (Resource.isValid())
|
||||
{
|
||||
QByteArray Data;
|
||||
|
||||
if (Resource.isCompressed())
|
||||
Data = qUncompress(Resource.data(), Resource.size());
|
||||
else
|
||||
Data = QByteArray::fromRawData((const char*)Resource.data(), Resource.size());
|
||||
|
||||
Reader.addData(QString::fromUtf8(Data));
|
||||
}
|
||||
}
|
||||
|
||||
if (!Reader.readNextStartElement() || Reader.name() != "LDrawMapping")
|
||||
return false;
|
||||
|
||||
bool Ok;
|
||||
|
||||
while (Reader.readNextStartElement())
|
||||
{
|
||||
if (Reader.name() == "Material")
|
||||
{
|
||||
int Lego, LDraw;
|
||||
LC_READ_XML_INT("lego", Lego);
|
||||
LC_READ_XML_INT("ldraw", LDraw);
|
||||
|
||||
MaterialTable[Lego] = LDraw;
|
||||
Reader.skipCurrentElement();
|
||||
}
|
||||
else if (Reader.name() == "Brick")
|
||||
{
|
||||
int Lego;
|
||||
LC_READ_XML_INT("lego", Lego);
|
||||
|
||||
BrickTable[Lego] = Reader.attributes().value("ldraw").toString().toLower();
|
||||
Reader.skipCurrentElement();
|
||||
}
|
||||
else if (Reader.name() == "Transformation")
|
||||
{
|
||||
float tx, ty, tz, ax, ay, az, Angle;
|
||||
LC_READ_XML_FLOAT("tx", tx);
|
||||
LC_READ_XML_FLOAT("ty", ty);
|
||||
LC_READ_XML_FLOAT("tz", tz);
|
||||
LC_READ_XML_FLOAT("ax", ax);
|
||||
LC_READ_XML_FLOAT("ay", ay);
|
||||
LC_READ_XML_FLOAT("az", az);
|
||||
LC_READ_XML_FLOAT("angle", Angle);
|
||||
|
||||
TransformationTable[Reader.attributes().value("ldraw").toString().toLower()] = lcLDDTransformation(QVector3D(-tx, -ty, -tz), lcLDDRotationMatrix(ax, ay, az, -180.0 * Angle / M_PI));
|
||||
Reader.skipCurrentElement();
|
||||
}
|
||||
else if (Reader.name() == "Assembly")
|
||||
{
|
||||
int Lego;
|
||||
LC_READ_XML_INT("lego", Lego);
|
||||
|
||||
QStringList Parts;
|
||||
while (Reader.readNextStartElement())
|
||||
{
|
||||
if (Reader.name() == "Part")
|
||||
Parts << Reader.attributes().value("ldraw").toString().toLower();
|
||||
|
||||
Reader.skipCurrentElement();
|
||||
}
|
||||
AssemblyTable[Lego] = lcLDDAssembly(Lego, Parts);
|
||||
}
|
||||
else
|
||||
{
|
||||
Reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
return !Reader.hasError();
|
||||
}
|
||||
|
||||
static QString lcLDDGetLDrawPart(int LegoID, const QMap<int, QString>& BrickTable)
|
||||
{
|
||||
if (BrickTable.contains(LegoID))
|
||||
return BrickTable.value(LegoID);
|
||||
return QString("%1.dat").arg(LegoID);
|
||||
}
|
||||
|
||||
static const lcLDDTransformation lcLDDGetLDrawTransform(const QString& LDraw, const QMap<QString, lcLDDTransformation>& TransformationTable)
|
||||
{
|
||||
return TransformationTable.value(LDraw);
|
||||
}
|
||||
|
||||
static int lcLDDGetLDrawColor(int LegoColor, const QMap<int, int>& MaterialTable)
|
||||
{
|
||||
if (MaterialTable.contains(LegoColor))
|
||||
return MaterialTable.value(LegoColor);
|
||||
return LegoColor;
|
||||
}
|
||||
|
||||
static bool lcLDDReadDecors(QMap<int, DecorMatch>& DecorationTable)
|
||||
{
|
||||
lcDiskFile DiskFile(lcGetPiecesLibrary()->mLibraryDir.absoluteFilePath(QLatin1String("decors_lxf2ldr.yaml")));
|
||||
lcMemFile MemFile;
|
||||
lcFile* File;
|
||||
|
||||
if (DiskFile.Open(QIODevice::ReadOnly))
|
||||
File = &DiskFile;
|
||||
else
|
||||
{
|
||||
QResource Resource(":/resources/decors_lxf2ldr.yaml");
|
||||
|
||||
if (Resource.isValid())
|
||||
{
|
||||
QByteArray Data;
|
||||
|
||||
if (Resource.isCompressed())
|
||||
Data = qUncompress(Resource.data(), Resource.size());
|
||||
else
|
||||
Data = QByteArray::fromRawData((const char*)Resource.data(), Resource.size());
|
||||
|
||||
MemFile.WriteBuffer(Data.constData(), Data.size());
|
||||
MemFile.Seek(0, SEEK_SET);
|
||||
File = &MemFile;
|
||||
}
|
||||
}
|
||||
|
||||
char Line[1024];
|
||||
int CurrentLegoId = -1;
|
||||
bool ParsingColors = true;
|
||||
int UseColor = 0;
|
||||
QList<lcLDDColorMap> Colors;
|
||||
lcLDDDecorationMap Decorations;
|
||||
|
||||
auto AddDecor = [&]()
|
||||
{
|
||||
if (CurrentLegoId == -1)
|
||||
return;
|
||||
|
||||
DecorationTable[CurrentLegoId] = DecorMatch(UseColor, Colors, Decorations);
|
||||
|
||||
UseColor = 0;
|
||||
Colors.clear();
|
||||
Decorations.clear();
|
||||
CurrentLegoId = -1;
|
||||
};
|
||||
|
||||
while (File->ReadLine(Line, sizeof(Line)))
|
||||
{
|
||||
char* Comment = strchr(Line, '#');
|
||||
if (Comment)
|
||||
*Comment = 0;
|
||||
|
||||
if (*Line == 0)
|
||||
{
|
||||
AddDecor();
|
||||
continue;
|
||||
}
|
||||
|
||||
int Indent = 0;
|
||||
for (char* c = Line; *c == ' '; c++)
|
||||
Indent++;
|
||||
|
||||
if (Indent == 0)
|
||||
{
|
||||
AddDecor();
|
||||
|
||||
if (!strchr(Line, ':'))
|
||||
continue;
|
||||
|
||||
CurrentLegoId = atoi(Line);
|
||||
}
|
||||
else if (Indent == 2)
|
||||
{
|
||||
char* Separator = strchr(Line, ':');
|
||||
if (!Separator)
|
||||
continue;
|
||||
*Separator = 0;
|
||||
Separator++;
|
||||
|
||||
if (!strcmp(Line + 2, "usecolor"))
|
||||
UseColor = atoi(Separator);
|
||||
else if (!strcmp(Line + 2, "colors"))
|
||||
ParsingColors = true;
|
||||
else if (!strcmp(Line + 2, "decorations"))
|
||||
ParsingColors = false;
|
||||
}
|
||||
else if (Indent == 4)
|
||||
{
|
||||
if (ParsingColors)
|
||||
{
|
||||
if (Line[4] == '-')
|
||||
Colors << lcLDDColorMap();
|
||||
}
|
||||
else
|
||||
{
|
||||
static const QMap<QString, QMatrix4x4> RotationTable =
|
||||
{
|
||||
{ "x", lcLDDRotationMatrix(1, 0, 0, 90) },
|
||||
{ "xx", lcLDDRotationMatrix(1, 0, 0, 180) },
|
||||
{ "xxx", lcLDDRotationMatrix(1, 0, 0, -90) },
|
||||
{ "y", lcLDDRotationMatrix(0, 1, 0, 90) },
|
||||
{ "yy", lcLDDRotationMatrix(0, 1, 0, 180) },
|
||||
{ "yyy", lcLDDRotationMatrix(0, 1, 0, -90) },
|
||||
{ "y7p/6", lcLDDRotationMatrix(0, 1, 0, 210) },
|
||||
{ "z", lcLDDRotationMatrix(0, 0, 1, 90) },
|
||||
{ "zz", lcLDDRotationMatrix(0, 0, 1, 180) },
|
||||
{ "zzz", lcLDDRotationMatrix(0, 0, 1, -90) },
|
||||
};
|
||||
|
||||
char* Separator = strchr(Line, ':');
|
||||
if (!Separator)
|
||||
continue;
|
||||
*Separator = 0;
|
||||
Separator++;
|
||||
|
||||
char* Key = Line + 4;
|
||||
|
||||
if (Key[0] != '\'')
|
||||
continue;
|
||||
Key++;
|
||||
|
||||
char* Quote = strchr(Key, '\'');
|
||||
if (!Quote)
|
||||
continue;
|
||||
*Quote = 0;
|
||||
|
||||
QStringList SubList = QString(Separator).trimmed().split(' ');
|
||||
QString LDrawFile = SubList.first().toLower();
|
||||
QString Rotation;
|
||||
if (SubList.size() > 1)
|
||||
Rotation = SubList.at(1);
|
||||
if (RotationTable.contains(Rotation))
|
||||
Decorations.insert(Key, lcLDDSubstitute(LDrawFile, new lcLDDTransformation(QVector3D(), RotationTable[Rotation])));
|
||||
else
|
||||
Decorations.insert(Key, lcLDDSubstitute(LDrawFile, 0));
|
||||
}
|
||||
}
|
||||
else if (Indent == 6)
|
||||
{
|
||||
if (ParsingColors)
|
||||
{
|
||||
char* Separator = strchr(Line, ':');
|
||||
if (!Separator)
|
||||
continue;
|
||||
*Separator = 0;
|
||||
Separator++;
|
||||
|
||||
int LegoColor = atoi(Line + 4);
|
||||
|
||||
QStringList SimpleList = QString(Separator).trimmed().split(' ');
|
||||
QString LDrawFile = SimpleList.first().toLower();
|
||||
bool Overwrite = false;
|
||||
if (SimpleList.size() > 1)
|
||||
Overwrite = SimpleList.at(1).toUpper() == QStringLiteral("OW");
|
||||
|
||||
if (!Colors.empty())
|
||||
Colors.last().insert(LegoColor, lcLDDSimpleSubstitute(LDrawFile, Overwrite));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void lcLDDGetDecorationSubstitute(int lego, const QString& decorations, const QList<int>& colors, int& usecolor, lcLDDSubstitute& substitute, const QMap<int, DecorMatch>& DecorationTable)
|
||||
{
|
||||
if (!DecorationTable.contains(lego))
|
||||
return;
|
||||
|
||||
const DecorMatch decor = DecorationTable.value(lego);
|
||||
usecolor = decor.UseColor;
|
||||
const int maxcol = qMin(colors.size(), decor.Colors.size());
|
||||
|
||||
for (int i = 0; i < maxcol; ++i)
|
||||
{
|
||||
const int curcol = colors.at(i) == 0 ? colors.first() : colors.at(i);
|
||||
if (decor.Colors.at(i).contains(curcol))
|
||||
{
|
||||
const lcLDDSimpleSubstitute sub = decor.Colors.at(i).value(curcol);
|
||||
if (substitute.LDrawFile.isEmpty() || sub.Overwrite)
|
||||
substitute = lcLDDSubstitute(sub.LDrawFile, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (decor.Decorations.contains(decorations))
|
||||
substitute = decor.Decorations.value(decorations);
|
||||
}
|
||||
|
||||
bool lcImportLDDFile(const QString& FileData, lcArray<lcPiece*>& Pieces, lcArray<lcArray<lcPiece*>>& Groups)
|
||||
{
|
||||
QMap<int, int> MaterialTable;
|
||||
QMap<int, QString> BrickTable;
|
||||
QMap<QString, lcLDDTransformation> TransformationTable;
|
||||
QMap<int, lcLDDAssembly> AssemblyTable;
|
||||
|
||||
if (!lcLDDReadLDrawXML(MaterialTable, BrickTable, TransformationTable, AssemblyTable))
|
||||
{
|
||||
QMessageBox::information(gMainWindow, QApplication::tr("Error"), QApplication::tr("Error loading conversion data from ldraw.xml."));
|
||||
return false;
|
||||
}
|
||||
|
||||
QMap<int, DecorMatch> DecorationTable;
|
||||
lcLDDReadDecors(DecorationTable);
|
||||
|
||||
QXmlStreamReader Reader(FileData);
|
||||
Reader.readNext();
|
||||
|
||||
if (!Reader.readNextStartElement() || Reader.name() != "LXFML")
|
||||
return false;
|
||||
|
||||
lcPiecesLibrary* Library = lcGetPiecesLibrary();
|
||||
bool Ok;
|
||||
|
||||
while (Reader.readNextStartElement())
|
||||
{
|
||||
if (Reader.name() == "Bricks")
|
||||
{
|
||||
while (Reader.readNextStartElement())
|
||||
{
|
||||
if (Reader.name() == "Brick")
|
||||
{
|
||||
int NumPieces = Pieces.GetSize();
|
||||
|
||||
while (Reader.readNextStartElement())
|
||||
{
|
||||
if (Reader.name() == "Part")
|
||||
{
|
||||
int DesignId;
|
||||
LC_READ_XML_INT("designID", DesignId);
|
||||
|
||||
const QString Decoration = Reader.attributes().value("decoration").toString();
|
||||
|
||||
const QStringList ColorList = Reader.attributes().value("materials").toString().split(',');
|
||||
QList<int> PartColors;
|
||||
for (const QString& color_txt : ColorList)
|
||||
{
|
||||
PartColors << color_txt.toInt(&Ok);
|
||||
if (!Ok)
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList Bones;
|
||||
while (Reader.readNextStartElement())
|
||||
{
|
||||
if (Reader.name() == "Bone")
|
||||
Bones << Reader.attributes().value("transformation").toString();
|
||||
Reader.skipCurrentElement();
|
||||
}
|
||||
|
||||
if (Bones.isEmpty())
|
||||
return false;
|
||||
|
||||
QList<QVector3D> Positions;
|
||||
QList<QMatrix4x4> Rotations;
|
||||
|
||||
for (const QString& Bone : Bones)
|
||||
{
|
||||
const QStringList FloatList = Bone.split(',');
|
||||
|
||||
if (FloatList.size() != 12)
|
||||
return false;
|
||||
|
||||
float Matrix[12];
|
||||
|
||||
for (int i = 0; i < FloatList.size(); ++i)
|
||||
{
|
||||
Matrix[i] = FloatList.at(i).toFloat(&Ok);
|
||||
if (!Ok)
|
||||
return false;
|
||||
}
|
||||
Positions << QVector3D(Matrix[9], Matrix[10], Matrix[11]);
|
||||
QMatrix4x4 Rotation(Matrix[0], Matrix[3], Matrix[6], 0, Matrix[1], Matrix[4], Matrix[7], 0, Matrix[2], Matrix[5], Matrix[8], 0, 0, 0, 0, 1);
|
||||
Rotation.optimize();
|
||||
Rotations << Rotation;
|
||||
}
|
||||
|
||||
QString PartID = lcLDDGetLDrawPart(DesignId, BrickTable);
|
||||
const lcLDDTransformation LDrawTransform = lcLDDGetLDrawTransform(PartID, TransformationTable);
|
||||
|
||||
int UseColor = 0;
|
||||
lcLDDSubstitute Substitute;
|
||||
lcLDDGetDecorationSubstitute(DesignId, Decoration, PartColors, UseColor, Substitute, DecorationTable);
|
||||
if (!Substitute.LDrawFile.isEmpty())
|
||||
PartID = Substitute.LDrawFile;
|
||||
|
||||
QList<int> LDrawColors;
|
||||
int ColorCode = lcLDDGetLDrawColor(PartColors.first(), MaterialTable);
|
||||
for (int Color : PartColors)
|
||||
LDrawColors << (Color ? lcLDDGetLDrawColor(Color, MaterialTable) : ColorCode);
|
||||
ColorCode = LDrawColors.at(UseColor);
|
||||
|
||||
const lcLDDTransformation *const SubTransform = Substitute.Transformation;
|
||||
const static QMatrix4x4 Axes = lcLDDRotationMatrix(1, 0, 0, 180);
|
||||
const static QVector3D Zero;
|
||||
|
||||
const QMatrix4x4 Rot = Rotations.first() * LDrawTransform.Rotation;
|
||||
const QMatrix4x4 ldr_rot = Axes * (SubTransform ? (Rot * SubTransform->Rotation) : Rot) * Axes;
|
||||
|
||||
const QVector3D Move = (SubTransform ? SubTransform->Translation : Zero) + LDrawTransform.Translation;
|
||||
const QVector3D ldr_pos = Axes * (Positions.first() + (Rot * Move)) * 25;
|
||||
|
||||
|
||||
lcMatrix44 LDrawMatrix(lcVector4(ldr_rot(0, 0), ldr_rot(1, 0), ldr_rot(2, 0), 0.0f), lcVector4(ldr_rot(0, 1), ldr_rot(1, 1), ldr_rot(2, 1), 0.0f),
|
||||
lcVector4(ldr_rot(0, 2), ldr_rot(1, 2), ldr_rot(2, 2), 0.0f), lcVector4(ldr_pos[0], ldr_pos[1], ldr_pos[2], 1.0f));
|
||||
|
||||
float* Matrix = LDrawMatrix;
|
||||
lcMatrix44 Transform(lcVector4(Matrix[0], Matrix[2], -Matrix[1], 0.0f), lcVector4(Matrix[8], Matrix[10], -Matrix[9], 0.0f),
|
||||
lcVector4(-Matrix[4], -Matrix[6], Matrix[5], 0.0f), lcVector4(Matrix[12], Matrix[14], -Matrix[13], 1.0f));
|
||||
|
||||
PartID = PartID.toUpper();
|
||||
PartID.chop(4);
|
||||
PieceInfo* Info = Library->FindPiece(PartID.toLatin1().constData(), nullptr, true, false);
|
||||
|
||||
lcPiece* Piece = new lcPiece(nullptr);
|
||||
Piece->SetPieceInfo(Info, false);
|
||||
Piece->Initialize(Transform, 1);
|
||||
Piece->SetColorCode(ColorCode);
|
||||
Pieces.Add(Piece);
|
||||
}
|
||||
else
|
||||
{
|
||||
Reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
if (Pieces.GetSize() != NumPieces + 1)
|
||||
{
|
||||
lcArray<lcPiece*> Group;
|
||||
for (int PieceIdx = NumPieces; PieceIdx < Pieces.GetSize(); PieceIdx++)
|
||||
Group.Add(Pieces[PieceIdx]);
|
||||
Groups.Add(Group);
|
||||
}
|
||||
}
|
||||
else
|
||||
Reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
else if (Reader.name() == "GroupSystems")
|
||||
{
|
||||
// todo: read ldd groups
|
||||
Reader.skipCurrentElement();
|
||||
}
|
||||
else
|
||||
Reader.skipCurrentElement();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
6
common/lc_lxf.h
Normal file
6
common/lc_lxf.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "lc_array.h"
|
||||
|
||||
bool lcImportLDDFile(const QString& FileData, lcArray<lcPiece*>& Pieces, lcArray<lcArray<lcPiece*>>& Groups);
|
||||
|
|
@ -378,6 +378,8 @@ void lcMainWindow::CreateMenus()
|
|||
FileMenu->addAction(mActions[LC_FILE_SAVE]);
|
||||
FileMenu->addAction(mActions[LC_FILE_SAVEAS]);
|
||||
FileMenu->addAction(mActions[LC_FILE_SAVE_IMAGE]);
|
||||
QMenu* ImportMenu = FileMenu->addMenu(tr("&Import"));
|
||||
ImportMenu->addAction(mActions[LC_FILE_IMPORT_LDD]);
|
||||
QMenu* ExportMenu = FileMenu->addMenu(tr("&Export"));
|
||||
ExportMenu->addAction(mActions[LC_FILE_EXPORT_3DS]);
|
||||
ExportMenu->addAction(mActions[LC_FILE_EXPORT_BRICKLINK]);
|
||||
|
@ -1922,6 +1924,26 @@ void lcMainWindow::MergeProject()
|
|||
}
|
||||
}
|
||||
|
||||
void lcMainWindow::ImportLDD()
|
||||
{
|
||||
if (!SaveProjectIfModified())
|
||||
return;
|
||||
|
||||
QString LoadFileName = QFileDialog::getOpenFileName(this, tr("Import"), QString(), tr("LEGO Diginal Designer Files (*.lxf);;All Files (*.*)"));
|
||||
if (LoadFileName.isEmpty())
|
||||
return;
|
||||
|
||||
Project* NewProject = new Project();
|
||||
|
||||
if (NewProject->ImportLDD(LoadFileName))
|
||||
{
|
||||
g_App->SetProject(NewProject);
|
||||
UpdateAllViews();
|
||||
}
|
||||
else
|
||||
delete NewProject;
|
||||
}
|
||||
|
||||
bool lcMainWindow::SaveProject(const QString& FileName)
|
||||
{
|
||||
QString SaveFileName;
|
||||
|
@ -2048,6 +2070,10 @@ void lcMainWindow::HandleCommand(lcCommandId CommandId)
|
|||
lcGetActiveProject()->SaveImage();
|
||||
break;
|
||||
|
||||
case LC_FILE_IMPORT_LDD:
|
||||
ImportLDD();
|
||||
break;
|
||||
|
||||
case LC_FILE_EXPORT_3DS:
|
||||
lcGetActiveProject()->Export3DStudio(QString());
|
||||
break;
|
||||
|
|
|
@ -251,6 +251,7 @@ public:
|
|||
void NewProject();
|
||||
bool OpenProject(const QString& FileName);
|
||||
void MergeProject();
|
||||
void ImportLDD();
|
||||
bool SaveProject(const QString& FileName);
|
||||
bool SaveProjectIfModified();
|
||||
bool SetModelFromFocus();
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "lc_qeditgroupsdialog.h"
|
||||
#include "lc_selectbycolordialog.h"
|
||||
#include "lc_qutils.h"
|
||||
#include "lc_lxf.h"
|
||||
|
||||
void lcModelProperties::LoadDefaults()
|
||||
{
|
||||
|
@ -944,6 +945,33 @@ bool lcModel::LoadBinary(lcFile* file)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool lcModel::LoadLDD(const QString& FileData)
|
||||
{
|
||||
lcArray<lcPiece*> Pieces;
|
||||
lcArray<lcArray<lcPiece*>> Groups;
|
||||
|
||||
if (!lcImportLDDFile(FileData, Pieces, Groups))
|
||||
return false;
|
||||
|
||||
for (lcPiece* Piece : Pieces)
|
||||
AddPiece(Piece);
|
||||
|
||||
for (const lcArray<lcPiece*>& Group : Groups)
|
||||
{
|
||||
lcGroup* NewGroup = AddGroup(tr("Group #"), nullptr);
|
||||
for (lcPiece* Piece : Group)
|
||||
Piece->SetGroup(NewGroup);
|
||||
}
|
||||
|
||||
lcPiecesLibrary* Library = lcGetPiecesLibrary();
|
||||
CalculateStep(mCurrentStep);
|
||||
Library->WaitForLoadQueue();
|
||||
Library->mBuffersDirty = true;
|
||||
Library->UnloadUnusedParts();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void lcModel::Merge(lcModel* Other)
|
||||
{
|
||||
for (int PieceIdx = 0; PieceIdx < Other->mPieces.GetSize(); PieceIdx++)
|
||||
|
|
|
@ -198,6 +198,7 @@ public:
|
|||
void SaveLDraw(QTextStream& Stream, bool SelectedOnly) const;
|
||||
void LoadLDraw(QIODevice& Device, Project* Project);
|
||||
bool LoadBinary(lcFile* File);
|
||||
bool LoadLDD(const QString& FileData);
|
||||
void SplitMPD(QIODevice& Device);
|
||||
void Merge(lcModel* Other);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "lc_application.h"
|
||||
#include "lc_profile.h"
|
||||
#include "lc_file.h"
|
||||
#include "lc_zipfile.h"
|
||||
#include "lc_qimagedialog.h"
|
||||
#include "lc_qmodellistdialog.h"
|
||||
#include "lc_qpovraydialog.h"
|
||||
|
@ -403,6 +404,53 @@ void Project::Merge(Project* Other)
|
|||
mModified = true;
|
||||
}
|
||||
|
||||
bool Project::ImportLDD(const QString& FileName)
|
||||
{
|
||||
lcZipFile ZipFile;
|
||||
|
||||
if (!ZipFile.OpenRead(FileName))
|
||||
return false;
|
||||
|
||||
lcMemFile XMLFile;
|
||||
if (!ZipFile.ExtractFile("IMAGE100.LXFML", XMLFile))
|
||||
return false;
|
||||
|
||||
mModels.DeleteAll();
|
||||
lcModel* Model = new lcModel(QString());
|
||||
|
||||
if (Model->LoadLDD(QString::fromUtf8((const char*)XMLFile.mBuffer)))
|
||||
{
|
||||
mModels.Add(Model);
|
||||
Model->SetSaved();
|
||||
}
|
||||
else
|
||||
delete Model;
|
||||
|
||||
if (mModels.IsEmpty())
|
||||
return false;
|
||||
|
||||
if (mModels.GetSize() == 1)
|
||||
{
|
||||
lcModel* Model = mModels[0];
|
||||
|
||||
if (Model->GetProperties().mName.isEmpty())
|
||||
Model->SetName(QFileInfo(FileName).completeBaseName());
|
||||
}
|
||||
|
||||
for (int ModelIdx = 0; ModelIdx < mModels.GetSize(); ModelIdx++)
|
||||
mModels[ModelIdx]->CreatePieceInfo(this);
|
||||
|
||||
lcArray<lcModel*> UpdatedModels;
|
||||
UpdatedModels.AllocGrow(mModels.GetSize());
|
||||
|
||||
for (int ModelIdx = 0; ModelIdx < mModels.GetSize(); ModelIdx++)
|
||||
mModels[ModelIdx]->UpdatePieceInfo(UpdatedModels);
|
||||
|
||||
mModified = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Project::GetModelParts(lcArray<lcModelPartsEntry>& ModelParts)
|
||||
{
|
||||
if (mModels.IsEmpty())
|
||||
|
|
|
@ -65,6 +65,7 @@ public:
|
|||
bool Save(const QString& FileName);
|
||||
bool Save(QTextStream& Stream);
|
||||
void Merge(Project* Other);
|
||||
bool ImportLDD(const QString& FileName);
|
||||
|
||||
void SaveImage();
|
||||
void Export3DStudio(const QString& FileName);
|
||||
|
|
|
@ -93,6 +93,8 @@
|
|||
<file>resources/library.zip</file>
|
||||
<file>resources/ldconfig.ldr</file>
|
||||
<file>resources/minifig.ini</file>
|
||||
<file>resources/ldraw.xml</file>
|
||||
<file>resources/decors_lxf2ldr.yaml</file>
|
||||
<file>resources/leocad_fr.qm</file>
|
||||
<file>resources/leocad_pt.qm</file>
|
||||
</qresource>
|
||||
|
|
699
resources/decors_lxf2ldr.yaml
Normal file
699
resources/decors_lxf2ldr.yaml
Normal file
|
@ -0,0 +1,699 @@
|
|||
---
|
||||
# Format:
|
||||
# ""
|
||||
# legoid:
|
||||
# usecolor: <index of the color used to paint the ldr part>
|
||||
# colors:
|
||||
# - # where
|
||||
# <lego color>: <ldr part file> [OW]
|
||||
# …
|
||||
# decorations:
|
||||
# <lxf decorations field>: <ldr part file> [rotation]
|
||||
# …
|
||||
# ""
|
||||
#
|
||||
# decorations beat colors.
|
||||
#
|
||||
# OW means that color beats previous colors.
|
||||
#
|
||||
# <rotation> is one of x, xx, xxx, y, yy, yyy, y7p/6
|
||||
# meaning resp. 90° around x, 180° around x, 270° around x, … y, … z, 210° around y.
|
||||
|
||||
93094:
|
||||
usecolor: 1
|
||||
colors:
|
||||
- # handle
|
||||
194: 93094.dat
|
||||
1: 25866c02.dat
|
||||
- # stick
|
||||
10066:
|
||||
colors:
|
||||
- # hair
|
||||
- # ears
|
||||
138: 10066p01.dat # dark tan
|
||||
312: 10066p02.dat # dark flesh
|
||||
330: 10066p03.dat # olive green
|
||||
10128:
|
||||
colors:
|
||||
- # body
|
||||
- # trousers
|
||||
268: 10128p01.dat # dark purple
|
||||
138: 10128p02.dat # dark tan
|
||||
- # ?
|
||||
- # hair
|
||||
10908:
|
||||
colors:
|
||||
- # chin
|
||||
- # face
|
||||
297: 10908p01.dat # gold
|
||||
310: 10908p01.dat # gold
|
||||
309: 10908p03.dat # silver
|
||||
315: 10908p03.dat # silver
|
||||
- # eyes
|
||||
1: 10908p01.dat # white
|
||||
23: 10908p02.dat OW # blue
|
||||
- # eyelids
|
||||
# 26: p0[1234] # black
|
||||
11055:
|
||||
colors:
|
||||
- # flag
|
||||
- # face 1
|
||||
- # face 2
|
||||
decorations:
|
||||
'57592,55510': 2335p03.dat
|
||||
11459:
|
||||
usecolor: 1
|
||||
colors:
|
||||
- # handle
|
||||
312: 11459p01.dat # dark flesh
|
||||
- # plunger
|
||||
13787:
|
||||
colors:
|
||||
- # hat
|
||||
37: 13787p01.dat # bright green
|
||||
- # ears
|
||||
13792:
|
||||
colors:
|
||||
- # mask
|
||||
- # glass
|
||||
26: 13792p01.dat # black (with stripes)
|
||||
13808:
|
||||
colors:
|
||||
- # handle
|
||||
- # body
|
||||
- # mouth
|
||||
26: 13808p01.dat # black
|
||||
15284:
|
||||
colors:
|
||||
- # hair
|
||||
- # visor
|
||||
22: 15284p01.dat # dark pink
|
||||
15400:
|
||||
usecolor: 1
|
||||
colors:
|
||||
- # brick
|
||||
199: 15400c01.dat # dark bluish grey
|
||||
- # top
|
||||
15427:
|
||||
colors:
|
||||
- # hair
|
||||
- # lock
|
||||
124: 15427p02.dat # magenta
|
||||
322: 15427p01.dat # magenta + medium azure
|
||||
decorations:
|
||||
'606285': 15427p01.dat
|
||||
16000:
|
||||
colors:
|
||||
- # arm
|
||||
- # lower arm
|
||||
24: 3818p01.dat # yellow
|
||||
16001:
|
||||
colors:
|
||||
- # arm
|
||||
- # lower arm
|
||||
24: 3819p01.dat # yellow
|
||||
16175:
|
||||
colors:
|
||||
- # helmet
|
||||
- # hair
|
||||
192: 16175p01.dat # reddish brown
|
||||
312: 16175p02.dat # medium dark flesh
|
||||
16178:
|
||||
colors:
|
||||
- # helmet
|
||||
- # hair
|
||||
308: 16178p01.dat # dark brown
|
||||
2634:
|
||||
colors:
|
||||
- # frame
|
||||
- # glass
|
||||
42: 2634p01.dat # trans light blue
|
||||
111: 2634p02.dat # trans black
|
||||
30152:
|
||||
usecolor: 1
|
||||
colors:
|
||||
- # glass
|
||||
41: 30152c02.dat # trans red
|
||||
40: 30152c01.dat # trans clear
|
||||
- # handle
|
||||
30258:
|
||||
colors:
|
||||
- # sign
|
||||
- # front
|
||||
decorations:
|
||||
'93337': 15210pc0.dat zz
|
||||
30261:
|
||||
colors:
|
||||
- # sign
|
||||
- # front
|
||||
decorations:
|
||||
'57818': 30261p02.dat
|
||||
30287:
|
||||
colors:
|
||||
- # hat
|
||||
- # fur
|
||||
1: 30287p01.dat # white
|
||||
30361:
|
||||
colors:
|
||||
- # cylinder
|
||||
- # front
|
||||
decorations:
|
||||
'86700': 30361dps1.dat yy
|
||||
'94274': 30361dps8.dat yy
|
||||
30367:
|
||||
colors:
|
||||
- # dome
|
||||
- # large band
|
||||
- # thin band
|
||||
- #
|
||||
- #
|
||||
- #
|
||||
decorations:
|
||||
'0,0,94270,94271,94272': 30367cps0.dat yy
|
||||
30480:
|
||||
colors:
|
||||
- # head
|
||||
- # eyes
|
||||
3: 30480ps0.dat # light yellow
|
||||
30483:
|
||||
colors:
|
||||
- # head
|
||||
- # nose
|
||||
26: 30483p01.dat # black
|
||||
- #
|
||||
- #
|
||||
30527:
|
||||
colors:
|
||||
- # tube
|
||||
- # stud tip
|
||||
26: 30527p01.dat # black
|
||||
27: 30527p02.dat # dark grey
|
||||
199: 30527p03.dat # dark bluish grey
|
||||
- # antistud tip
|
||||
26: 30527p01.dat # black
|
||||
27: 30527p02.dat # dark grey
|
||||
199: 30527p03.dat # dark bluish grey
|
||||
45406:
|
||||
colors:
|
||||
- # cockpit
|
||||
- # glass
|
||||
111: 45406c01.dat # trans black
|
||||
40: 45406c02.dat # trans clear
|
||||
42: 45406c03.dat # trans light blue
|
||||
54654:
|
||||
usecolor: 1
|
||||
colors:
|
||||
- # bottom
|
||||
194: 54654c02.dat # light bluish grey
|
||||
199: 54654c03.dat # dark bluish grey
|
||||
106: 54654c04.dat # orange
|
||||
1: 54654c06.dat # white
|
||||
- # top
|
||||
- # tip
|
||||
1: 54654c05.dat # white
|
||||
54779:
|
||||
usecolor: 1
|
||||
colors:
|
||||
- # top
|
||||
194: 54779p01.dat # light bluish grey
|
||||
199: 54779p02.dat # dark bluish grey
|
||||
- # bottom
|
||||
54923:
|
||||
colors:
|
||||
- # cockpit
|
||||
- # glass
|
||||
111: 54923c01.dat # trans black
|
||||
42: 54923c02.dat # trans light blue
|
||||
57028:
|
||||
colors:
|
||||
- # arrow
|
||||
- # head
|
||||
26: 57028a.dat # black
|
||||
119: 57028b.dat # lime
|
||||
194: 57028c.dat # grey
|
||||
199: 57028c.dat # grey
|
||||
208: 57028c.dat # grey
|
||||
2: 57028c.dat # grey
|
||||
27: 57028c.dat # grey
|
||||
24: 57028d.dat # yellow
|
||||
60672:
|
||||
usecolor: 1
|
||||
colors:
|
||||
- # arm
|
||||
298: 60672c01.dat # pearlescent grey
|
||||
315: 60672c01.dat # pearlescent grey
|
||||
309: 60672c01.dat # pearlescent grey
|
||||
179: 60672c01.dat # pearlescent grey
|
||||
316: 60672c01.dat # pearlescent grey
|
||||
139: 60672c02.dat # pearlescent copper
|
||||
- # skin
|
||||
60673:
|
||||
usecolor: 1
|
||||
colors:
|
||||
- # arm
|
||||
298: 60673c01.dat # pearlescent grey
|
||||
315: 60673c01.dat # pearlescent grey
|
||||
309: 60673c01.dat # pearlescent grey
|
||||
179: 60673c01.dat # pearlescent grey
|
||||
316: 60673c01.dat # pearlescent grey
|
||||
139: 60673c02.dat # pearlescent copper
|
||||
- # skin
|
||||
60797:
|
||||
colors:
|
||||
- # door
|
||||
- # glass
|
||||
42: 60797c01.dat # trans light blue
|
||||
111: 60797c02.dat # trans black
|
||||
192: 60797c03.dat # reddish brown
|
||||
61406:
|
||||
colors:
|
||||
- # spike
|
||||
- # tip
|
||||
24: 61406p01.dat # yellow
|
||||
194: 61406p02.dat # light bluish grey
|
||||
106: 61406p03.dat # orange
|
||||
119: 61406p04.dat # lime
|
||||
26: 61406p05.dat # black
|
||||
62537:
|
||||
colors:
|
||||
- # underside
|
||||
- # left side
|
||||
26: 62537p02.dat # black
|
||||
23: 62537p01.dat # blue
|
||||
- # pompoms
|
||||
23: 62537p01.dat # blue # (one)
|
||||
1: 62537p02.dat # white
|
||||
21: 62537p03.dat # red # (one)
|
||||
- # (don’t work)
|
||||
- # (don’t work)
|
||||
- # right side
|
||||
21: 62537p03.dat # red
|
||||
6567:
|
||||
colors:
|
||||
- # windscreen
|
||||
- # glass
|
||||
40: 6567p01.dat # trans clear
|
||||
111: 6567p02.dat # trans black
|
||||
42: 6567p03.dat # trans light blue
|
||||
76029:
|
||||
colors:
|
||||
- # window
|
||||
- # glass
|
||||
111: 76029c01.dat # trans black
|
||||
43: 76029c02.dat # trans blue
|
||||
42: 76029c03.dat # trans light blue
|
||||
40: 76029c04.dat # trans clear
|
||||
48: 76029c05.dat # trans green
|
||||
76033:
|
||||
colors:
|
||||
- # window
|
||||
- # glass
|
||||
43: 76033c01.dat # trans dark blue
|
||||
42: 76033c02.dat # trans light blue
|
||||
76040:
|
||||
usecolor: 1
|
||||
colors:
|
||||
- # base
|
||||
199: 76040c05.dat # dark bluish grey
|
||||
27: 76040c04.dat # dark grey
|
||||
192: 76040c06.dat # reddish brown
|
||||
- # top
|
||||
76041:
|
||||
colors:
|
||||
- # door
|
||||
- # glass
|
||||
40: 76041c01.dat # trans clear
|
||||
85947:
|
||||
colors:
|
||||
- #
|
||||
- # eye? (don’t work)
|
||||
- # tongue
|
||||
- # "=1 eye? (don’t work)"
|
||||
- #
|
||||
decorations:
|
||||
'0,0,0,93500': 85947p01.dat
|
||||
'0,0,93849,93500': 85947p01.dat
|
||||
85959:
|
||||
usecolor: 1
|
||||
colors:
|
||||
- # flame
|
||||
182: 85959p01.dat # trans orange
|
||||
44: 85959p02.dat # trans yellow
|
||||
48: 85959p03.dat # trans green
|
||||
40: 85959p04.dat # trans clear
|
||||
227: 85959p05.dat # trans bright green
|
||||
126: 85959p06.dat # trans purple
|
||||
- # base
|
||||
- #
|
||||
- #
|
||||
decorations:
|
||||
'87354,87355,0': 85959p01.dat
|
||||
'87354,0,0': 85959p01.dat
|
||||
'0,87355,0': 85959p01.dat
|
||||
'0,87354,87355': 85959p01.dat
|
||||
90391:
|
||||
colors:
|
||||
- # staff
|
||||
- # blade
|
||||
179: 90391p02.dat # flat silver
|
||||
315: 90391p01.dat # metallic silver
|
||||
309: 90391p01.dat # metallic silver
|
||||
90393:
|
||||
colors:
|
||||
- # handle
|
||||
- # mike
|
||||
315: 90393p01.dat # metallic silver
|
||||
309: 90393p01.dat # metallic silver
|
||||
9044:
|
||||
colors:
|
||||
- # base
|
||||
- # tap
|
||||
309: 9044c02.dat # chrome
|
||||
315: 9044c02.dat # chrome
|
||||
2: 9044c01.dat # light grey
|
||||
90462:
|
||||
colors:
|
||||
- # wig
|
||||
- # front stud
|
||||
- #
|
||||
decorations:
|
||||
'92597': 90462bpq1.dat
|
||||
92254:
|
||||
colors:
|
||||
- # hair
|
||||
- # hat
|
||||
26: 92254p01.dat # black
|
||||
124: 92254p02.dat # magenta
|
||||
93549:
|
||||
usecolor: 1
|
||||
colors:
|
||||
- # bottle
|
||||
40: 93549c01.dat # trans clear
|
||||
- # content
|
||||
93552:
|
||||
colors:
|
||||
- # paintbrush
|
||||
- # brush tip
|
||||
28: 93552p01.dat # green
|
||||
- # ring
|
||||
179: 93552p01.dat # flat silver
|
||||
93564:
|
||||
colors:
|
||||
- # guitar
|
||||
- # plugs
|
||||
- #
|
||||
- #
|
||||
decorations:
|
||||
'0,600099,600385': 93564p02.dat
|
||||
'0,95101,96912': 93564p01.dat
|
||||
93568:
|
||||
colors:
|
||||
- # pie
|
||||
- # cream
|
||||
1: 93568p01.dat # white
|
||||
24: 93568p02.dat # yellow
|
||||
decorations:
|
||||
'97265': 93568p01.dat
|
||||
95330:
|
||||
colors:
|
||||
- # handle
|
||||
- # head
|
||||
21: 95330p01.dat # red
|
||||
- # blade
|
||||
315: 95330p01.dat # silver
|
||||
309: 95330p01.dat # silver
|
||||
179: 95330p01.dat # silver
|
||||
98382:
|
||||
colors:
|
||||
- # bear
|
||||
- # sole
|
||||
- # muzzle
|
||||
5: 98382p01.dat # tan
|
||||
- # belly?
|
||||
- #
|
||||
decorations:
|
||||
'0,99596,73156,0': 98382p01.dat
|
||||
98388:
|
||||
colors:
|
||||
- # bird
|
||||
- # beak
|
||||
124: 98388p03.dat # magenta
|
||||
21: 98388p01.dat # red
|
||||
24: 98388p02.dat # yellow
|
||||
- #
|
||||
- #
|
||||
98568:
|
||||
colors:
|
||||
- # sword
|
||||
- # blade
|
||||
227: 98568p01.dat # trans bright green
|
||||
179: 98568p02.dat # flat silver
|
||||
143: 98568p03.dat # trans medium blue
|
||||
99013:
|
||||
colors:
|
||||
- # blade
|
||||
- # tip
|
||||
26: 99013p01.dat # black
|
||||
99243:
|
||||
colors:
|
||||
- # mask
|
||||
- # feathers tips
|
||||
- # right eye + jaw
|
||||
- #
|
||||
decorations:
|
||||
'600100,600949,600950': 99243p01.dat
|
||||
2431:
|
||||
decorations:
|
||||
'55728': 2431pc0.dat
|
||||
'58858': 2431bp52.dat
|
||||
'600778': 2431p01.dat
|
||||
'610633': 2431p03.dat
|
||||
2528:
|
||||
decorations:
|
||||
'601244': 2528p30.dat
|
||||
3003:
|
||||
decorations:
|
||||
'57239,57308': 3003pe2.dat
|
||||
'607795,0': 3003px1.dat
|
||||
'610491,0': 3003px0.dat
|
||||
'88625,88624': 3003pe3.dat
|
||||
3004:
|
||||
decorations:
|
||||
'610489,0,0': 3004ptc1.dat
|
||||
3005:
|
||||
decorations:
|
||||
'56918': 3005pe1.dat
|
||||
'88620': 3005pe4.dat
|
||||
'88627': 3005pe4.dat
|
||||
'95551': 3005pf0.dat
|
||||
3010:
|
||||
decorations:
|
||||
'618499,0': 3010pb1.dat
|
||||
3039:
|
||||
decorations:
|
||||
'55123': 3039pce.dat
|
||||
'55132': 3039pc9.dat
|
||||
'55159': 3039pca.dat
|
||||
'56057': 3039pc6.dat
|
||||
'56571': 3039pcb.dat
|
||||
'86666': 3039pcc.dat
|
||||
3040:
|
||||
decorations:
|
||||
'55161': 3040p06.dat
|
||||
3068:
|
||||
decorations:
|
||||
'610486': 3068bpx1.dat
|
||||
'63404': 3068bp33.dat
|
||||
'73023': 3068bpt3.dat
|
||||
'55124': 3068bp72.dat
|
||||
'55350': 3068bp72.dat
|
||||
'97353': 3068bp71.dat
|
||||
3069:
|
||||
decorations:
|
||||
'55035': 3069bpc3.dat
|
||||
'55128': 3069bps1.dat
|
||||
'55347': 3069bps6.dat yy
|
||||
'55506': 3069bpw2.dat
|
||||
'55513': 3069bp02.dat yy
|
||||
'56756': 3069bp08.dat yy
|
||||
'58229': 3069bp0c.dat
|
||||
'60382': 3069bpc1.dat yy
|
||||
'609694': 3069bpw4.dat yy
|
||||
'609700': 3069bpw3.dat yy
|
||||
'609713': 3069bpc7.dat yy
|
||||
'62292': 3069bp01.dat
|
||||
'93074': 3069bp17.dat
|
||||
'55160': 3069bp80.dat
|
||||
'58812': 3069bp80.dat
|
||||
3070:
|
||||
decorations:
|
||||
'55071': 3070bp07.dat yyy
|
||||
3678:
|
||||
decorations:
|
||||
'0,85232': 3678bp4x.dat
|
||||
3846:
|
||||
decorations:
|
||||
'602054': 3846p4j.dat
|
||||
4150:
|
||||
decorations:
|
||||
'55729': 4150ps4.dat
|
||||
'59487': 4150p03.dat
|
||||
'87078': 4150p02.dat
|
||||
4492:
|
||||
decorations:
|
||||
'58002,58000': 4492p02.dat
|
||||
12888:
|
||||
decorations:
|
||||
'603963,603962': 12888p01.dat
|
||||
13789:
|
||||
decorations:
|
||||
'605406': 13789p01.dat
|
||||
'605407': 13792p01.dat
|
||||
14769:
|
||||
decorations:
|
||||
'55729': 14769p06.dat
|
||||
'606885': 14769p04.dat yy
|
||||
'606886': 14769p02.dat yy
|
||||
'606887': 14769p01.dat yy
|
||||
'87078': 14769p07.dat
|
||||
15210:
|
||||
decorations:
|
||||
'93337': 15210pc0.dat zz
|
||||
15530:
|
||||
decorations:
|
||||
'606112': 15530p01.dat
|
||||
19727:
|
||||
decorations:
|
||||
'611560': 19727p01.dat
|
||||
19729:
|
||||
decorations:
|
||||
'610378': 19729p02.dat
|
||||
'611551': 19729p01.dat
|
||||
30126:
|
||||
decorations:
|
||||
'88247': 30126p01.dat
|
||||
30372:
|
||||
decorations:
|
||||
'58425': 30372ps0.dat
|
||||
32474:
|
||||
decorations:
|
||||
'606117': 32474p01.dat y
|
||||
44336:
|
||||
decorations:
|
||||
'87833': 44336p01.dat
|
||||
44341:
|
||||
decorations:
|
||||
'87834': 44341p01.dat
|
||||
44342:
|
||||
decorations:
|
||||
'87835': 44342p01.dat
|
||||
44343:
|
||||
decorations:
|
||||
'87836': 44343p01.dat
|
||||
44375:
|
||||
decorations:
|
||||
'60488': 44375p03.dat
|
||||
59231:
|
||||
decorations:
|
||||
'59645': 59231p4h.dat
|
||||
75902:
|
||||
decorations:
|
||||
'604009': 75902p03.dat
|
||||
85984:
|
||||
decorations:
|
||||
'611013,0,0': 85984p70.dat
|
||||
'616009,0,0': 85984pc1.dat
|
||||
90397:
|
||||
decorations:
|
||||
'95059': 90397p02.dat
|
||||
90508:
|
||||
decorations:
|
||||
'92125': 90508p01.dat
|
||||
91884:
|
||||
decorations:
|
||||
'600331': 91884p04.dat
|
||||
'95056': 91884p03.dat
|
||||
'99762': 91884p02.dat
|
||||
93551:
|
||||
decorations:
|
||||
'94470': 93551p01.dat
|
||||
95228:
|
||||
decorations:
|
||||
'97373': 95228p01.dat
|
||||
98138:
|
||||
decorations:
|
||||
'603159': 98138p07.dat y7p/6
|
||||
'610549': 98138p0c.dat
|
||||
'610752': 98138p0b.dat
|
||||
98372:
|
||||
decorations:
|
||||
'99754,99590': 98372p01.dat
|
||||
98384:
|
||||
decorations:
|
||||
'99598': 98384p01.dat
|
||||
3626:
|
||||
decorations:
|
||||
'55196,0,0': 3626cp01.dat
|
||||
'59715,0,0': 3626bp06.dat
|
||||
'606096,0,0': 3626bpq3.dat
|
||||
'64901,0,0': 3626bp3r.dat
|
||||
'89320,0,0': 3626cp8k.dat
|
||||
'93417,0,0': 3626bp61.dat
|
||||
'94062,0,0': 3626bpq2.dat
|
||||
'94097,0,0': 3626bpq4.dat
|
||||
'99567,0,0': 3626bp05.dat
|
||||
'99571,0,0': 3626cp8c.dat
|
||||
'0,0,608148': 3626cp8e.dat yy
|
||||
3814:
|
||||
decorations:
|
||||
'55059,0': 973p8z.dat
|
||||
'55127,0': 973p8j.dat
|
||||
'55129,0': 973p6j.dat
|
||||
'55661,0': 973p8x.dat
|
||||
'55662,0': 973p7q.dat
|
||||
'55663,0': 973p7u.dat
|
||||
'55663,93077': 973p7n.dat
|
||||
'55665,0': 973p7v.dat
|
||||
'56288,0': 973p1r.dat
|
||||
'56289,0': 973p7h.dat
|
||||
'56753,0': 973p8g.dat
|
||||
'57056,0': 973p7z.dat
|
||||
'57497,0': 973p2d.dat
|
||||
'60153,0': 973p1j.dat
|
||||
'606424,0': 973p8i.dat
|
||||
'608149,0': 973p91.dat
|
||||
'610390,0': 973p90.dat
|
||||
'612774,612775': 973p8s.dat
|
||||
'612842,612843': 973p8r.dat
|
||||
'612844,612845': 973p8q.dat
|
||||
'88183,0': 973pc11.dat
|
||||
'89174,0': 973ps1.dat
|
||||
'89309,89310': 973p7w.dat
|
||||
'89311,89312': 973p7j.dat
|
||||
'91323,0': 973pc23.dat
|
||||
'92100,0': 973pr5.dat
|
||||
'93200,0': 973p7t.dat
|
||||
'93319,93338': 973p7m.dat
|
||||
'93429,0': 973pc3g.dat
|
||||
'96692,97941': 973p7y.dat
|
||||
'99158,99157': 973p8k.dat
|
||||
'99672,0': 973pc67.dat
|
||||
3815:
|
||||
decorations:
|
||||
'606647,0': 3815p8i.dat
|
||||
'95112,0': 3815pc44.dat
|
||||
'99713,0': 3815pc67.dat
|
||||
3816:
|
||||
decorations:
|
||||
'73244,0,0': 3816pba.dat
|
||||
'95030,0,0': 3816pc44.dat
|
||||
'99716,605096,0': 3816pc67.dat
|
||||
'99716,99717,0': 3816pc67.dat
|
||||
'0,602300,0': 3816paw.dat
|
||||
3817:
|
||||
decorations:
|
||||
'606649,0,0': 3817p8h.dat
|
||||
'95031,0,0': 3817pc44.dat
|
||||
'99718,605097,0': 3817pc67.dat
|
||||
'99718,99719,0': 3817pc67.dat
|
||||
'0,602298,0': 3817paw.dat
|
17477
resources/ldraw.xml
Normal file
17477
resources/ldraw.xml
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue