Added support for drawing submodels.

This commit is contained in:
leo 2014-12-24 15:52:52 +00:00
parent ffc58f554c
commit 788f0bf9e4
13 changed files with 222 additions and 58 deletions

View file

@ -354,7 +354,7 @@ void lcContext::DrawOpaqueMeshes(const lcMatrix44& ViewMatrix, const lcArray<lcR
lcMesh* Mesh = RenderMesh.Mesh;
BindMesh(Mesh);
SetWorldViewMatrix(lcMul(*RenderMesh.WorldMatrix, ViewMatrix));
SetWorldViewMatrix(lcMul(RenderMesh.WorldMatrix, ViewMatrix));
for (int SectionIdx = 0; SectionIdx < Mesh->mNumSections; SectionIdx++)
{
@ -414,7 +414,7 @@ void lcContext::DrawTranslucentMeshes(const lcMatrix44& ViewMatrix, const lcArra
lcMesh* Mesh = RenderMesh.Mesh;
BindMesh(Mesh);
SetWorldViewMatrix(lcMul(*RenderMesh.WorldMatrix, ViewMatrix));
SetWorldViewMatrix(lcMul(RenderMesh.WorldMatrix, ViewMatrix));
for (int SectionIdx = 0; SectionIdx < Mesh->mNumSections; SectionIdx++)
{

View file

@ -60,28 +60,25 @@ void lcPiecesLibrary::Unload()
mZipFiles[LC_ZIPFILE_UNOFFICIAL] = NULL;
}
PieceInfo* lcPiecesLibrary::FindPiece(const char* PieceName, bool CreatePlaceholderIfMissing)
PieceInfo* lcPiecesLibrary::FindPiece(const char* PieceName, bool CreatePlaceholder)
{
for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++)
if (!strcmp(PieceName, mPieces[PieceIdx]->m_strName))
return mPieces[PieceIdx];
if (CreatePlaceholderIfMissing)
return CreatePlaceholder(PieceName);
if (CreatePlaceholder)
{
PieceInfo* Info = new PieceInfo();
Info->CreatePlaceholder(PieceName);
mPieces.Add(Info);
return Info;
}
return NULL;
}
PieceInfo* lcPiecesLibrary::CreatePlaceholder(const char* PieceName)
{
PieceInfo* Info = new PieceInfo();
Info->CreatePlaceholder(PieceName);
mPieces.Add(Info);
return Info;
}
lcTexture* lcPiecesLibrary::FindTexture(const char* TextureName)
{
for (int TextureIdx = 0; TextureIdx < mTextures.GetSize(); TextureIdx++)
@ -747,7 +744,7 @@ void lcPiecesLibrary::SaveCacheFile()
{
PieceInfo* Info = mPieces[PieceIdx];
if (Info->mFlags & LC_PIECE_PLACEHOLDER)
if (Info->mFlags & LC_PIECE_PLACEHOLDER || Info->mFlags & LC_PIECE_MODEL)
continue;
bool Cached = (Info->mFlags & LC_PIECE_CACHED) != 0;

View file

@ -119,8 +119,7 @@ public:
bool Load(const char* LibraryPath, const char* CachePath);
void Unload();
PieceInfo* FindPiece(const char* PieceName, bool CreatePlaceholderIfMissing);
PieceInfo* CreatePlaceholder(const char* PieceName);
PieceInfo* FindPiece(const char* PieceName, bool CreatePlaceholder);
bool LoadPiece(PieceInfo* Info);
bool LoadBuiltinPieces();

View file

@ -168,7 +168,7 @@ public:
struct lcRenderMesh
{
lcMatrix44* WorldMatrix;
lcMatrix44 WorldMatrix;
lcMesh* Mesh;
int ColorIndex;
float Distance;

View file

@ -149,6 +149,7 @@ lcModel::lcModel(const QString& Name)
mCurrentStep = 1;
mBackgroundTexture = NULL;
mPieceInfo = NULL;
}
lcModel::~lcModel()
@ -157,6 +158,18 @@ lcModel::~lcModel()
DeleteHistory();
}
bool lcModel::IncludesModel(const lcModel* Model) const
{
if (Model == this)
return true;
for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++)
if (mPieces[PieceIdx]->mPieceInfo->IncludesModel(Model))
return true;
return false;
}
void lcModel::DeleteHistory()
{
mUndoHistory.DeleteAll();
@ -185,6 +198,13 @@ void lcModel::DeleteModel()
mGroups.DeleteAll();
}
void lcModel::CreatePieceInfo()
{
QString PartID = mProperties.mName.toUpper();
mPieceInfo = lcGetPiecesLibrary()->FindPiece(PartID.toLatin1().constData(), true);
mPieceInfo->SetModel(this);
}
void lcModel::SaveLDraw(QTextStream& Stream, bool SelectedOnly) const
{
QLatin1String LineEnding("\r\n");
@ -295,6 +315,7 @@ void lcModel::LoadLDraw(QTextStream& Stream)
while (!Stream.atEnd())
{
qint64 Pos = Stream.pos();
QString Line = Stream.readLine().trimmed();
QTextStream LineStream(&Line, QIODevice::ReadOnly);
@ -307,10 +328,16 @@ void lcModel::LoadLDraw(QTextStream& Stream)
if (Token == QLatin1String("FILE"))
{
if (!mProperties.mName.isEmpty())
{
Stream.seek(Pos);
break;
}
mProperties.mName = LineStream.readAll().trimmed();
continue;
}
else if (Token == QLatin1String("ENDFILE"))
else if (Token == QLatin1String("NOFILE"))
{
break;
}
@ -860,8 +887,6 @@ void lcModel::GetScene(lcScene& Scene, lcCamera* ViewCamera, bool DrawInterface)
Scene.TranslucentMeshes.AllocGrow(mPieces.GetSize());
Scene.InterfaceObjects.RemoveAll();
const lcMatrix44& ViewMatrix = ViewCamera->mWorldView;
for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++)
{
lcPiece* Piece = mPieces[PieceIdx];
@ -883,7 +908,7 @@ void lcModel::GetScene(lcScene& Scene, lcCamera* ViewCamera, bool DrawInterface)
Selected = false;
}
Info->AddRenderMeshes(ViewMatrix, &Piece->mModelWorld, Piece->mColorIndex, Focused, Selected, Scene.OpaqueMeshes, Scene.TranslucentMeshes);
Info->AddRenderMeshes(Scene, Piece->mModelWorld, Piece->mColorIndex, Focused, Selected);
if (Selected)
Scene.InterfaceObjects.Add(Piece);
@ -912,6 +937,31 @@ void lcModel::GetScene(lcScene& Scene, lcCamera* ViewCamera, bool DrawInterface)
Scene.TranslucentMeshes.Sort(lcTranslucentRenderMeshCompare);
}
void lcModel::AddRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, bool Focused, bool Selected) const
{
// todo: use last step
for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++)
{
lcPiece* Piece = mPieces[PieceIdx];
if (!Piece->IsVisible(mCurrentStep))
continue;
int ColorIndex = Piece->mColorIndex;
if (ColorIndex == gDefaultColor)
ColorIndex = DefaultColorIndex;
PieceInfo* Info = Piece->mPieceInfo;
Info->AddRenderMeshes(Scene, lcMul(Piece->mModelWorld, WorldMatrix), ColorIndex, Focused, Selected);
}
// todo: add model bounding box
// if (Selected)
// Scene.InterfaceObjects.Add(Piece);
}
void lcModel::DrawBackground(lcContext* Context)
{
if (mProperties.mBackgroundType == LC_BACKGROUND_SOLID)

View file

@ -118,6 +118,14 @@ public:
return mSavedHistory != mUndoHistory[0];
}
bool IncludesModel(const lcModel* Model) const;
void CreatePieceInfo();
PieceInfo* GetPieceInfo() const
{
return mPieceInfo;
}
const lcArray<lcPiece*>& GetPieces() const
{
return mPieces;
@ -200,6 +208,7 @@ public:
void Paste();
void GetScene(lcScene& Scene, lcCamera* ViewCamera, bool DrawInterface) const;
void AddRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, bool Focused, bool Selected) const;
void DrawBackground(lcContext* Context);
void RayTest(lcObjectRayTest& ObjectRayTest) const;
@ -303,6 +312,7 @@ protected:
void SelectGroup(lcGroup* TopGroup, bool Select);
lcModelProperties mProperties;
PieceInfo* mPieceInfo;
lcStep mCurrentStep;
lcVector3 mMouseToolDistance;

View file

@ -1053,7 +1053,7 @@ void MinifigWizard::OnDraw()
for (int PieceIdx = 0; PieceIdx < LC_MFW_NUMITEMS; PieceIdx++)
if (mMinifig->Parts[PieceIdx])
mMinifig->Parts[PieceIdx]->AddRenderMeshes(ViewMatrix, &mMinifig->Matrices[PieceIdx], mMinifig->Colors[PieceIdx], false, false, OpaqueMeshes, TranslucentMeshes);
mMinifig->Parts[PieceIdx]->AddRenderMeshes(ViewMatrix, mMinifig->Matrices[PieceIdx], mMinifig->Colors[PieceIdx], false, false, OpaqueMeshes, TranslucentMeshes);
OpaqueMeshes.Sort(lcOpaqueRenderMeshCompare);
mContext->DrawOpaqueMeshes(ViewMatrix, OpaqueMeshes);

View file

@ -7,6 +7,9 @@
#include "pieceinf.h"
#include "lc_library.h"
#include "lc_application.h"
#include "lc_model.h"
#include "lc_context.h"
#include "camera.h"
PieceInfo::PieceInfo()
{
@ -15,6 +18,7 @@ PieceInfo::PieceInfo()
mFlags = 0;
mMesh = NULL;
mRefCount = 0;
mModel = NULL;
}
PieceInfo::~PieceInfo()
@ -23,6 +27,31 @@ PieceInfo::~PieceInfo()
Unload();
}
void PieceInfo::SetModel(lcModel* Model)
{
m_strName[0] = 0;
m_strDescription[0] = 0;
mFlags = LC_PIECE_MODEL;
mModel = Model;
delete mMesh;
mMesh = NULL;
}
bool PieceInfo::IncludesModel(const lcModel* Model) const
{
if (mFlags & LC_PIECE_MODEL)
{
if (mModel == Model)
return true;
return mModel->IncludesModel(Model);
}
return false;
}
void PieceInfo::CreatePlaceholder(const char* Name)
{
strncpy(m_strName, Name, sizeof(m_strName));
@ -55,16 +84,19 @@ void PieceInfo::Load()
void PieceInfo::Unload()
{
for (int SectionIdx = 0; SectionIdx < mMesh->mNumSections; SectionIdx++)
if (mMesh)
{
lcMeshSection& Section = mMesh->mSections[SectionIdx];
for (int SectionIdx = 0; SectionIdx < mMesh->mNumSections; SectionIdx++)
{
lcMeshSection& Section = mMesh->mSections[SectionIdx];
if (Section.Texture)
Section.Texture->Release();
if (Section.Texture)
Section.Texture->Release();
}
delete mMesh;
mMesh = NULL;
}
delete mMesh;
mMesh = NULL;
}
// Zoom extents for the preview window and print catalog
@ -113,7 +145,38 @@ void PieceInfo::RenderPiece(int nColor)
mMesh->Render(nColor, false, false);
}
void PieceInfo::AddRenderMeshes(const lcMatrix44& ViewMatrix, lcMatrix44* WorldMatrix, int ColorIndex, bool Focused, bool Selected, lcArray<lcRenderMesh>& OpaqueMeshes, lcArray<lcRenderMesh>& TranslucentMeshes)
void PieceInfo::AddRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMatrix, int ColorIndex, bool Focused, bool Selected)
{
if (mFlags & LC_PIECE_MODEL)
{
mModel->AddRenderMeshes(Scene, WorldMatrix, ColorIndex, Focused, Selected);
return;
}
lcRenderMesh RenderMesh;
RenderMesh.WorldMatrix = WorldMatrix;
RenderMesh.Mesh = mMesh;
RenderMesh.ColorIndex = ColorIndex;
RenderMesh.Focused = Focused;
RenderMesh.Selected = Selected;
bool Translucent = lcIsColorTranslucent(ColorIndex);
if ((mFlags & (LC_PIECE_HAS_SOLID | LC_PIECE_HAS_LINES)) || ((mFlags & LC_PIECE_HAS_DEFAULT) && !Translucent))
Scene.OpaqueMeshes.Add(RenderMesh);
if ((mFlags & LC_PIECE_HAS_TRANSLUCENT) || ((mFlags & LC_PIECE_HAS_DEFAULT) && Translucent))
{
lcVector3 Pos = lcMul31(WorldMatrix[3], Scene.Camera->mWorldView);
RenderMesh.Distance = Pos[2];
Scene.TranslucentMeshes.Add(RenderMesh);
}
}
void PieceInfo::AddRenderMeshes(const lcMatrix44& ViewMatrix, const lcMatrix44& WorldMatrix, int ColorIndex, bool Focused, bool Selected, lcArray<lcRenderMesh>& OpaqueMeshes, lcArray<lcRenderMesh>& TranslucentMeshes)
{
lcRenderMesh RenderMesh;
@ -130,7 +193,7 @@ void PieceInfo::AddRenderMeshes(const lcMatrix44& ViewMatrix, lcMatrix44* WorldM
if ((mFlags & LC_PIECE_HAS_TRANSLUCENT) || ((mFlags & LC_PIECE_HAS_DEFAULT) && Translucent))
{
lcVector3 Pos = lcMul31((*WorldMatrix)[3], ViewMatrix);
lcVector3 Pos = lcMul31(WorldMatrix[3], ViewMatrix);
RenderMesh.Distance = Pos[2];

View file

@ -15,6 +15,7 @@
#define LC_PIECE_HAS_LINES 0x08 // Piece has lines
#define LC_PIECE_PLACEHOLDER 0x10 // Placeholder for a piece not in the library
#define LC_PIECE_CACHED 0x20 // Piece is saved in the library cache
#define LC_PIECE_MODEL 0x40 // Piece if a model
#define LC_PIECE_NAME_LEN 256
@ -83,10 +84,14 @@ public:
// Operations
void ZoomExtents(float Fov, float Aspect, float* EyePos = NULL) const;
void RenderPiece(int nColor);
void AddRenderMeshes(const lcMatrix44& ViewMatrix, lcMatrix44* WorldMatrix, int ColorIndex, bool Focused, bool Selected, lcArray<lcRenderMesh>& OpaqueMeshes, lcArray<lcRenderMesh>& TranslucentMeshes);
void AddRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMatrix, int ColorIndex, bool Focused, bool Selected);
void AddRenderMeshes(const lcMatrix44& ViewMatrix, const lcMatrix44& WorldMatrix, int ColorIndex, bool Focused, bool Selected, lcArray<lcRenderMesh>& OpaqueMeshes, lcArray<lcRenderMesh>& TranslucentMeshes);
void CreatePlaceholder(const char* Name);
void SetModel(lcModel* Model);
bool IncludesModel(const lcModel* Model) const;
public:
lcMesh* mMesh;
@ -100,6 +105,7 @@ public:
protected:
int mRefCount;
lcModel* mModel;
void Load();
void Unload();

View file

@ -198,8 +198,7 @@ bool Project::Load(const QString& FileName)
while (!Stream.atEnd())
{
QString Name = tr("Model%1").arg(QString::number(mModels.GetSize() + 1));
lcModel* Model = new lcModel(Name);
lcModel* Model = new lcModel(QString());
mModels.Add(Model);
Model->LoadLDraw(Stream);
Model->SetSaved();
@ -212,7 +211,7 @@ bool Project::Load(const QString& FileName)
MemFile.WriteBuffer(FileData.constData(), FileData.size());
MemFile.Seek(0, SEEK_SET);
lcModel* Model = new lcModel(tr("Model1"));
lcModel* Model = new lcModel(QString());
if (Model->LoadBinary(&MemFile))
{
@ -223,11 +222,21 @@ bool Project::Load(const QString& FileName)
delete Model;
}
// todo: validate model names
if (mModels.IsEmpty())
return false;
for (int ModelIdx = 0; ModelIdx < mModels.GetSize(); ModelIdx++)
{
lcModel* Model = mModels[ModelIdx];
if (Model->GetProperties().mName.isEmpty())
Model->SetName(tr("Model #%1").arg(QString::number(ModelIdx + 1)));
// todo: validate model names
Model->CreatePieceInfo();
}
mActiveModel = mModels[0];

View file

@ -602,7 +602,7 @@ void lcQMainWindow::partsTreeItemChanged(QTreeWidgetItem *current, QTreeWidgetIt
if (!current)
return;
PieceInfo *info = (PieceInfo*)current->data(0, lcQPartsTree::PartInfoRole).value<void*>();
PieceInfo *info = (PieceInfo*)current->data(0, lcQPartsTree::PieceInfoRole).value<void*>();
if (info)
{
@ -1286,6 +1286,8 @@ void lcQMainWindow::updateModels()
else
Action->setVisible(false);
}
partsTree->UpdateModels();
}
void lcQMainWindow::updateCategories()

View file

@ -4,6 +4,8 @@
#include "lc_category.h"
#include "lc_library.h"
#include "pieceinf.h"
#include "project.h"
#include "lc_model.h"
static int lcQPartsTreeSortFunc(PieceInfo* const& a, PieceInfo* const& b)
{
@ -25,11 +27,12 @@ static int lcQPartsTreeSortFunc(PieceInfo* const& a, PieceInfo* const& b)
return 0;
}
lcQPartsTree::lcQPartsTree(QWidget *parent) :
QTreeWidget(parent)
lcQPartsTree::lcQPartsTree(QWidget* Parent)
: QTreeWidget(Parent)
{
setDragEnabled(true);
setHeaderHidden(true);
setUniformRowHeights(true);
connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(itemExpanded(QTreeWidgetItem*)));
updateCategories();
@ -83,13 +86,36 @@ void lcQPartsTree::updateCategories()
new QTreeWidgetItem(categoryItem);
}
searchResultsItem = new QTreeWidgetItem(this, QStringList(tr("Search Results")));
mModelListItem = new QTreeWidgetItem(this, QStringList(tr("Models")));
mSearchResultsItem = new QTreeWidgetItem(this, QStringList(tr("Search Results")));
}
void lcQPartsTree::UpdateModels()
{
while (QTreeWidgetItem* Item = mModelListItem->child(0))
delete Item;
const lcArray<lcModel*>& Models = lcGetActiveProject()->GetModels();
lcModel* CurrentModel = lcGetActiveModel();
for (int ModelIdx = 0; ModelIdx < Models.GetSize(); ModelIdx++)
{
lcModel* Model = Models[ModelIdx];
if (!Model->IncludesModel(CurrentModel))
{
const lcModelProperties& Properties = Model->GetProperties();
QTreeWidgetItem* Item = new QTreeWidgetItem(mModelListItem, QStringList(Properties.mName));
Item->setData(0, PieceInfoRole, qVariantFromValue((void*)Model->GetPieceInfo()));
Item->setToolTip(0, Properties.mDescription);
}
}
}
void lcQPartsTree::searchParts(const QString& searchString)
{
while (QTreeWidgetItem *item = searchResultsItem->child(0))
delete item;
while (QTreeWidgetItem* Item = mSearchResultsItem->child(0))
delete Item;
lcPiecesLibrary* library = lcGetPiecesLibrary();
lcArray<PieceInfo*> singleParts, groupedParts;
@ -101,21 +127,21 @@ void lcQPartsTree::searchParts(const QString& searchString)
{
PieceInfo* partInfo = singleParts[partIndex];
QTreeWidgetItem* partItem = new QTreeWidgetItem(searchResultsItem, QStringList(partInfo->m_strDescription));
partItem->setData(0, PartInfoRole, qVariantFromValue((void*)partInfo));
QTreeWidgetItem* partItem = new QTreeWidgetItem(mSearchResultsItem, QStringList(partInfo->m_strDescription));
partItem->setData(0, PieceInfoRole, qVariantFromValue((void*)partInfo));
partItem->setToolTip(0, QString("%1 (%2)").arg(partInfo->m_strDescription, partInfo->m_strName));
}
setCurrentItem(searchResultsItem);
expandItem(searchResultsItem);
scrollToItem(searchResultsItem, PositionAtTop);
setCurrentItem(mSearchResultsItem);
expandItem(mSearchResultsItem);
scrollToItem(mSearchResultsItem, PositionAtTop);
}
void lcQPartsTree::itemExpanded(QTreeWidgetItem *expandedItem)
{
QTreeWidgetItem *parent = expandedItem->parent();
if (parent || expandedItem == searchResultsItem)
if (parent || expandedItem == mModelListItem || expandedItem == mSearchResultsItem)
return;
if (expandedItem->data(0, ExpandedOnceRole).toBool())
@ -140,7 +166,7 @@ void lcQPartsTree::itemExpanded(QTreeWidgetItem *expandedItem)
PieceInfo* partInfo = singleParts[partIndex];
QTreeWidgetItem* partItem = new QTreeWidgetItem(expandedItem, QStringList(partInfo->m_strDescription));
partItem->setData(0, PartInfoRole, qVariantFromValue((void*)partInfo));
partItem->setData(0, PieceInfoRole, qVariantFromValue((void*)partInfo));
partItem->setToolTip(0, QString("%1 (%2)").arg(partInfo->m_strDescription, partInfo->m_strName));
if (groupedParts.FindIndex(partInfo) != -1)
@ -162,7 +188,7 @@ void lcQPartsTree::itemExpanded(QTreeWidgetItem *expandedItem)
desc += len;
QTreeWidgetItem* patternedItem = new QTreeWidgetItem(partItem, QStringList(desc));
patternedItem->setData(0, PartInfoRole, qVariantFromValue((void*)patternedInfo));
patternedItem->setData(0, PieceInfoRole, qVariantFromValue((void*)patternedInfo));
patternedItem->setToolTip(0, QString("%1 (%2)").arg(patternedInfo->m_strDescription, patternedInfo->m_strName));
}
}
@ -200,7 +226,7 @@ void lcQPartsTree::setCurrentPart(PieceInfo *part)
for (int itemIndex = 0; itemIndex < categoryItem->childCount(); itemIndex++)
{
QTreeWidgetItem *item = categoryItem->child(itemIndex);
PieceInfo *info = (PieceInfo*)item->data(0, lcQPartsTree::PartInfoRole).value<void*>();
PieceInfo *info = (PieceInfo*)item->data(0, PieceInfoRole).value<void*>();
if (info == parentPart)
{
@ -215,7 +241,7 @@ void lcQPartsTree::setCurrentPart(PieceInfo *part)
for (int itemIndex = 0; itemIndex < categoryItem->childCount(); itemIndex++)
{
QTreeWidgetItem *item = categoryItem->child(itemIndex);
PieceInfo *info = (PieceInfo*)item->data(0, lcQPartsTree::PartInfoRole).value<void*>();
PieceInfo *info = (PieceInfo*)item->data(0, PieceInfoRole).value<void*>();
if (info == part)
{
@ -228,7 +254,7 @@ void lcQPartsTree::setCurrentPart(PieceInfo *part)
void lcQPartsTree::startDrag(Qt::DropActions supportedActions)
{
PieceInfo *info = (PieceInfo*)currentItem()->data(0, lcQPartsTree::PartInfoRole).value<void*>();
PieceInfo *info = (PieceInfo*)currentItem()->data(0, PieceInfoRole).value<void*>();
if (!info)
return;

View file

@ -15,12 +15,13 @@ public:
void startDrag(Qt::DropActions supportedActions);
void updateCategories();
void UpdateModels();
void searchParts(const QString& searchString);
void setCurrentPart(PieceInfo *part);
enum
{
PartInfoRole = Qt::UserRole,
PieceInfoRole = Qt::UserRole,
CategoryRole,
ExpandedOnceRole
};
@ -32,7 +33,8 @@ public slots:
void itemExpanded(QTreeWidgetItem *item);
private:
QTreeWidgetItem *searchResultsItem;
QTreeWidgetItem* mModelListItem;
QTreeWidgetItem* mSearchResultsItem;
};
#endif // LC_QPARTSTREE_H