Multithreaded piece loading.

This commit is contained in:
Leonardo Zide
2017-01-22 19:28:05 -08:00
parent e3f5be649e
commit 8c318cbdf1
13 changed files with 312 additions and 504 deletions
+146 -19
View File
@@ -14,6 +14,7 @@
#include <ctype.h>
#include <locale.h>
#include <zlib.h>
#include <QtConcurrent/QtConcurrent>
#if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
@@ -26,6 +27,7 @@
#define LC_LIBRARY_CACHE_DIRECTORY 0x0002
lcPiecesLibrary::lcPiecesLibrary()
: mLoadMutex(QMutex::Recursive)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
QStringList cachePathList = QStandardPaths::standardLocations(QStandardPaths::CacheLocation);
@@ -48,6 +50,10 @@ lcPiecesLibrary::lcPiecesLibrary()
lcPiecesLibrary::~lcPiecesLibrary()
{
mLoadMutex.lock();
mLoadQueue.clear();
mLoadMutex.unlock();
WaitForLoadQueue();
Unload();
}
@@ -74,6 +80,8 @@ void lcPiecesLibrary::Unload()
void lcPiecesLibrary::RemoveTemporaryPieces()
{
QMutexLocker LoadLock(&mLoadMutex);
for (int PieceIdx = mPieces.GetSize() - 1; PieceIdx >= 0; PieceIdx--)
{
PieceInfo* Info = mPieces[PieceIdx];
@@ -81,7 +89,7 @@ void lcPiecesLibrary::RemoveTemporaryPieces()
if (!Info->IsTemporary())
break;
if (!Info->IsLoaded())
if (Info->GetRefCount() == 0)
{
mPieces.RemoveIndex(PieceIdx);
delete Info;
@@ -233,6 +241,11 @@ bool lcPiecesLibrary::OpenArchive(const char* FileName, lcZipFileType ZipFileTyp
return true;
}
static int lcPrimitiveCompare(lcLibraryPrimitive* const& a, lcLibraryPrimitive* const& b)
{
return strcmp(a->mName, b->mName);
}
bool lcPiecesLibrary::OpenArchive(lcFile* File, const char* FileName, lcZipFileType ZipFileType)
{
lcZipFile* ZipFile = new lcZipFile();
@@ -324,7 +337,7 @@ bool lcPiecesLibrary::OpenArchive(lcFile* File, const char* FileName, lcZipFileT
int PrimitiveIndex = FindPrimitiveIndex(Name);
if (PrimitiveIndex == -1)
mPrimitives.Add(new lcLibraryPrimitive(Name, ZipFileType, FileIdx, false, true));
mPrimitives.AddSorted(new lcLibraryPrimitive(Name, ZipFileType, FileIdx, false, true), lcPrimitiveCompare);
else
mPrimitives[PrimitiveIndex]->SetZipFile(ZipFileType, FileIdx);
}
@@ -336,7 +349,7 @@ bool lcPiecesLibrary::OpenArchive(lcFile* File, const char* FileName, lcZipFileT
int PrimitiveIndex = FindPrimitiveIndex(Name);
if (PrimitiveIndex == -1)
mPrimitives.Add(new lcLibraryPrimitive(Name, ZipFileType, FileIdx, (memcmp(Name, "STU", 3) == 0), false));
mPrimitives.AddSorted(new lcLibraryPrimitive(Name, ZipFileType, FileIdx, (memcmp(Name, "STU", 3) == 0), false), lcPrimitiveCompare);
else
mPrimitives[PrimitiveIndex]->SetZipFile(ZipFileType, FileIdx);
}
@@ -586,7 +599,7 @@ bool lcPiecesLibrary::OpenDirectory(const char* Path)
bool SubFile = SubFileDirectories[DirectoryIdx];
lcLibraryPrimitive* Prim = new lcLibraryPrimitive(Name, LC_NUM_ZIPFILES, 0, !SubFile && (memcmp(Name, "STU", 3) == 0), SubFile);
mPrimitives.Add(Prim);
mPrimitives.AddSorted(Prim, lcPrimitiveCompare);
}
}
@@ -849,16 +862,23 @@ bool lcPiecesLibrary::LoadCachePiece(PieceInfo* Info)
if (!ReadCacheFile(FileName, MeshData))
return false;
lcMesh* Mesh = new lcMesh;
Info->SetMesh(Mesh);
quint32 Flags;
if (MeshData.ReadBuffer((char*)&Flags, sizeof(Flags)) == 0)
return false;
Info->mFlags = Flags;
return Mesh->FileLoad(MeshData);
lcMesh* Mesh = new lcMesh;
if (Mesh->FileLoad(MeshData))
{
Info->SetMesh(Mesh);
return true;
}
else
{
delete Mesh;
return false;
}
}
bool lcPiecesLibrary::SaveCachePiece(PieceInfo* Info)
@@ -877,6 +897,89 @@ bool lcPiecesLibrary::SaveCachePiece(PieceInfo* Info)
return WriteCacheFile(FileName, MeshData);
}
static void lcLoadPieceFuture(lcPiecesLibrary* Library)
{
Library->LoadQueuedPiece();
}
void lcPiecesLibrary::LoadPieceInfo(PieceInfo* Info, bool Wait, bool Priority)
{
QMutexLocker LoadLock(&mLoadMutex);
if (Wait)
{
if (Info->AddRef() == 1)
Info->Load();
else
{
if (Info->mState == LC_PIECEINFO_UNLOADED)
{
Info->Load();
emit PartLoaded(Info);
}
else
{
LoadLock.unlock();
while (Info->mState != LC_PIECEINFO_LOADED)
QThread::msleep(10);
}
}
}
else
{
if (Info->AddRef() == 1)
{
if (Priority)
mLoadQueue.prepend(Info);
else
mLoadQueue.append(Info);
mLoadFutures.append(QtConcurrent::run(lcLoadPieceFuture, this));
}
}
}
void lcPiecesLibrary::ReleasePieceInfo(PieceInfo* Info)
{
QMutexLocker LoadLock(&mLoadMutex);
if (Info->GetRefCount() == 0 || Info->Release() == 0)
Info->Unload();
}
void lcPiecesLibrary::LoadQueuedPiece()
{
mLoadMutex.lock();
PieceInfo* Info = NULL;
while (!mLoadQueue.isEmpty())
{
Info = mLoadQueue.takeFirst();
if (Info->mState == LC_PIECEINFO_UNLOADED && Info->GetRefCount() > 0)
{
Info->mState = LC_PIECEINFO_LOADING;
break;
}
}
mLoadMutex.unlock();
if (Info)
Info->Load();
emit PartLoaded(Info);
}
void lcPiecesLibrary::WaitForLoadQueue()
{
for (QFuture<void>& Future : mLoadFutures)
Future.waitForFinished();
mLoadFutures.clear();
}
struct lcMergeSection
{
lcLibraryMeshSection* Shared;
@@ -920,14 +1023,13 @@ static int LibraryMeshSectionCompare(lcMergeSection const& First, lcMergeSection
return a->mColor > b->mColor ? -1 : 1;
}
bool lcPiecesLibrary::LoadPiece(PieceInfo* Info)
bool lcPiecesLibrary::LoadPieceData(PieceInfo* Info)
{
lcLibraryMeshData MeshData;
lcArray<lcLibraryTextureMap> TextureStack;
bool Loaded = false;
bool SaveCache = false;
bool UpdateBoundingBox = false;
if (Info->mZipFileType != LC_NUM_ZIPFILES && mZipFiles[Info->mZipFileType])
{
@@ -967,10 +1069,7 @@ bool lcPiecesLibrary::LoadPiece(PieceInfo* Info)
if (!Loaded)
return false;
lcMesh* Mesh = CreateMesh(Info, MeshData);
if (UpdateBoundingBox)
Info->SetBoundingBox(Mesh->mBoundingBox.Min, Mesh->mBoundingBox.Max);
CreateMesh(Info, MeshData);
if (SaveCache)
SaveCachePiece(Info);
@@ -1332,8 +1431,14 @@ void lcPiecesLibrary::UpdateBuffers(lcContext* Context)
void lcPiecesLibrary::UnloadUnusedParts()
{
QMutexLocker LoadLock(&mLoadMutex);
for (int PieceInfoIndex = 0; PieceInfoIndex < mPieces.GetSize(); PieceInfoIndex++)
mPieces[PieceInfoIndex]->UnloadIfUnused();
{
PieceInfo* Info = mPieces[PieceInfoIndex];
if (Info->GetRefCount() == 0 && Info->mState != LC_PIECEINFO_UNLOADED)
ReleasePieceInfo(Info);
}
}
bool lcPiecesLibrary::LoadTexture(lcTexture* Texture)
@@ -1369,15 +1474,37 @@ bool lcPiecesLibrary::LoadTexture(lcTexture* Texture)
int lcPiecesLibrary::FindPrimitiveIndex(const char* Name) const
{
for (int PrimitiveIndex = 0; PrimitiveIndex < mPrimitives.GetSize(); PrimitiveIndex++)
if (!strcmp(mPrimitives[PrimitiveIndex]->mName, Name))
return PrimitiveIndex;
int Count = mPrimitives.GetSize();
int Begin = 0;
int Middle;
return -1;
if (Count == 0)
return -1;
while (Count > 0)
{
int Half = Count >> 1;
Middle = Begin + Half;
if (strcmp(mPrimitives[Middle]->mName, Name) < 0)
{
Begin = Middle + 1;
Count -= Half + 1;
}
else
{
Count = Half;
}
}
if (Begin != mPrimitives.GetSize() && !strcmp(mPrimitives[Begin]->mName, Name))
return Begin;
else
return -1;
}
bool lcPiecesLibrary::LoadPrimitive(int PrimitiveIndex)
{
QMutexLocker LoadLock(&mLoadMutex);
lcLibraryPrimitive* Primitive = mPrimitives[PrimitiveIndex];
lcArray<lcLibraryTextureMap> TextureStack;
+15 -2
View File
@@ -123,8 +123,10 @@ public:
lcLibraryMeshData mMeshData;
};
class lcPiecesLibrary
class lcPiecesLibrary : public QObject
{
Q_OBJECT
public:
lcPiecesLibrary();
~lcPiecesLibrary();
@@ -135,8 +137,12 @@ public:
void RemovePiece(PieceInfo* Info);
PieceInfo* FindPiece(const char* PieceName, Project* Project, bool CreatePlaceholder, bool SearchProjectFolder);
bool LoadPiece(PieceInfo* Info);
void LoadPieceInfo(PieceInfo* Info, bool Wait, bool Priority);
void ReleasePieceInfo(PieceInfo* Info);
bool LoadBuiltinPieces();
bool LoadPieceData(PieceInfo* Info);
void LoadQueuedPiece();
void WaitForLoadQueue();
lcTexture* FindTexture(const char* TextureName);
bool LoadTexture(lcTexture* Texture);
@@ -176,6 +182,9 @@ public:
lcVertexBuffer mVertexBuffer;
lcIndexBuffer mIndexBuffer;
signals:
void PartLoaded(PieceInfo* Info);
protected:
bool OpenArchive(const char* FileName, lcZipFileType ZipFileType);
bool OpenArchive(lcFile* File, const char* FileName, lcZipFileType ZipFileType);
@@ -192,6 +201,10 @@ protected:
int FindPrimitiveIndex(const char* Name) const;
bool LoadPrimitive(int PrimitiveIndex);
QMutex mLoadMutex;
QList<QFuture<void>> mLoadFutures;
QList<PieceInfo*> mLoadQueue;
QString mCachePath;
qint64 mArchiveCheckSum[4];
char mLibraryFileName[LC_MAXPATH];
+5 -3
View File
@@ -54,7 +54,8 @@ lcMainWindow::~lcMainWindow()
{
if (mCurrentPieceInfo)
{
mCurrentPieceInfo->Release();
lcPiecesLibrary* Library = lcGetPiecesLibrary();
Library->ReleasePieceInfo(mCurrentPieceInfo);
mCurrentPieceInfo = NULL;
}
@@ -1265,15 +1266,16 @@ void lcMainWindow::SetTransformType(lcTransformType TransformType)
void lcMainWindow::SetCurrentPieceInfo(PieceInfo* Info)
{
lcPiecesLibrary* Library = lcGetPiecesLibrary();
GetActiveView()->MakeCurrent();
if (mCurrentPieceInfo)
mCurrentPieceInfo->Release();
Library->ReleasePieceInfo(mCurrentPieceInfo);
mCurrentPieceInfo = Info;
if (mCurrentPieceInfo)
mCurrentPieceInfo->AddRef();
Library->LoadPieceInfo(mCurrentPieceInfo, true, true);
}
lcVector3 lcMainWindow::GetTransformAmount()
+18 -12
View File
@@ -168,7 +168,9 @@ lcModel::~lcModel()
if (mPieceInfo->GetModel() == this)
mPieceInfo->SetPlaceholder();
mPieceInfo->Release();
lcPiecesLibrary* Library = lcGetPiecesLibrary();
Library->ReleasePieceInfo(mPieceInfo);
}
DeleteModel();
@@ -225,9 +227,10 @@ void lcModel::DeleteModel()
void lcModel::CreatePieceInfo(Project* Project)
{
mPieceInfo = lcGetPiecesLibrary()->FindPiece(mProperties.mName.toUpper().toLatin1().constData(), Project, true, false);
lcPiecesLibrary* Library = lcGetPiecesLibrary();
mPieceInfo = Library->FindPiece(mProperties.mName.toUpper().toLatin1().constData(), Project, true, false);
mPieceInfo->SetModel(this, true);
mPieceInfo->AddRef();
Library->LoadPieceInfo(mPieceInfo, true, true);
}
void lcModel::UpdatePieceInfo(lcArray<lcModel*>& UpdatedModels)
@@ -468,6 +471,7 @@ void lcModel::LoadLDraw(QIODevice& Device, Project* Project)
lcArray<lcGroup*> CurrentGroups;
lcArray<lcPieceControlPoint> ControlPoints;
int CurrentStep = 1;
lcPiecesLibrary* Library = lcGetPiecesLibrary();
mProperties.mAuthor.clear();
@@ -609,8 +613,6 @@ void lcModel::LoadLDraw(QIODevice& Device, Project* Project)
if (PartID.endsWith(QLatin1String(".DAT")))
PartID = PartID.left(PartID.size() - 4);
lcPiecesLibrary* Library = lcGetPiecesLibrary();
if (Library->IsPrimitive(PartID.toLatin1().constData()))
{
mFileLines.append(OriginalLine);
@@ -633,7 +635,7 @@ void lcModel::LoadLDraw(QIODevice& Device, Project* Project)
lcVector4(-Matrix[4], -Matrix[6], Matrix[5], 0.0f), lcVector4(Matrix[12], Matrix[14], -Matrix[13], 1.0f));
Piece->SetFileLine(mFileLines.size());
Piece->SetPieceInfo(Info);
Piece->SetPieceInfo(Info, false);
Piece->Initialize(Transform, CurrentStep);
Piece->SetColorCode(ColorCode);
Piece->SetControlPoints(ControlPoints);
@@ -648,7 +650,9 @@ void lcModel::LoadLDraw(QIODevice& Device, Project* Project)
mCurrentStep = CurrentStep;
CalculateStep(mCurrentStep);
UpdateBackgroundTexture();
lcGetPiecesLibrary()->UnloadUnusedParts();
Library->WaitForLoadQueue();
Library->mBuffersDirty = true;
Library->UnloadUnusedParts();
delete Piece;
delete Camera;
@@ -1348,12 +1352,13 @@ void lcModel::SaveCheckpoint(const QString& Description)
void lcModel::LoadCheckPoint(lcModelHistoryEntry* CheckPoint)
{
lcPiecesLibrary* Library = lcGetPiecesLibrary();
lcArray<PieceInfo*> Infos;
for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++)
{
PieceInfo* Info = mPieces[PieceIdx]->mPieceInfo;
Info->AddRef();
Library->LoadPieceInfo(Info, true, true);
Infos.Add(Info);
}
@@ -1370,7 +1375,7 @@ void lcModel::LoadCheckPoint(lcModelHistoryEntry* CheckPoint)
gMainWindow->UpdateAllViews();
for (int InfoIdx = 0; InfoIdx < Infos.GetSize(); InfoIdx++)
Infos[InfoIdx]->Release();
Library->ReleasePieceInfo(Infos[InfoIdx]);
}
void lcModel::SetActive(bool Active)
@@ -1989,7 +1994,7 @@ void lcModel::InsertPiece(lcPiece* Piece, int Index)
{
lcMesh* Mesh = Info->IsTemporary() ? gPlaceholderMesh : Info->GetMesh();
if (Mesh->mVertexCacheOffset == -1)
if (Mesh && Mesh->mVertexCacheOffset == -1)
lcGetPiecesLibrary()->mBuffersDirty = true;
}
@@ -2582,8 +2587,9 @@ void lcModel::SetSelectedPiecesPieceInfo(PieceInfo* Info)
if (Piece->IsSelected() && Piece->mPieceInfo != Info)
{
Piece->mPieceInfo->Release();
Piece->SetPieceInfo(Info);
lcPiecesLibrary* Library = lcGetPiecesLibrary();
Library->ReleasePieceInfo(Piece->mPieceInfo);
Piece->SetPieceInfo(Info, true);
Modified = true;
}
}
+56 -26
View File
@@ -69,23 +69,44 @@ lcPartSelectionListModel::lcPartSelectionListModel(QObject* Parent)
{
mListView = (lcPartSelectionListView*)Parent;
mIconSize = 0;
mLastDrawTime = QDateTime::currentDateTime();
connect(lcGetPiecesLibrary(), SIGNAL(PartLoaded(PieceInfo*)), this, SLOT(PartLoaded(PieceInfo*)));
}
lcPartSelectionListModel::~lcPartSelectionListModel()
{
ClearRequests();
}
void lcPartSelectionListModel::ClearRequests()
{
lcPiecesLibrary* Library = lcGetPiecesLibrary();
foreach(int RequestIdx, mRequestedPreviews)
{
PieceInfo* Info = mParts[RequestIdx].first;
Library->ReleasePieceInfo(Info);
}
mRequestedPreviews.clear();
}
void lcPartSelectionListModel::Redraw()
{
ClearRequests();
beginResetModel();
for (int PartIdx = 0; PartIdx < mParts.size(); PartIdx++)
mParts[PartIdx].second = QPixmap();
mRequestedPreviews.clear();
endResetModel();
}
void lcPartSelectionListModel::SetCategory(int CategoryIndex)
{
ClearRequests();
beginResetModel();
lcPiecesLibrary* Library = lcGetPiecesLibrary();
@@ -99,17 +120,16 @@ void lcPartSelectionListModel::SetCategory(int CategoryIndex)
for (int PartIdx = 0; PartIdx < SingleParts.GetSize(); PartIdx++)
mParts[PartIdx] = QPair<PieceInfo*, QPixmap>(SingleParts[PartIdx], QPixmap());
mRequestedPreviews.clear();
endResetModel();
}
void lcPartSelectionListModel::SetModelsCategory()
{
ClearRequests();
beginResetModel();
mParts.clear();
mRequestedPreviews.clear();
const lcArray<lcModel*>& Models = lcGetActiveProject()->GetModels();
lcModel* CurrentModel = lcGetActiveModel();
@@ -193,21 +213,34 @@ void lcPartSelectionListModel::RequestPreview(int InfoIndex)
if (!mIconSize || !mParts[InfoIndex].second.isNull())
return;
mRequestedPreviews.removeOne(InfoIndex);
mRequestedPreviews.append(InfoIndex);
DrawPreview();
if (mRequestedPreviews.indexOf(InfoIndex) != -1)
return;
PieceInfo* Info = mParts[InfoIndex].first;
lcGetPiecesLibrary()->LoadPieceInfo(Info, false, false);
if (Info->mState == LC_PIECEINFO_LOADED)
DrawPreview(InfoIndex);
else
mRequestedPreviews.append(InfoIndex);
}
void lcPartSelectionListModel::DrawPreview()
void lcPartSelectionListModel::PartLoaded(PieceInfo* Info)
{
qint64 Elapsed = mLastDrawTime.msecsTo(QDateTime::currentDateTime());
if (Elapsed < 100)
for (int PartIdx = 0; PartIdx < mParts.size(); PartIdx++)
{
QTimer::singleShot(100 - Elapsed, this, SLOT(DrawPreview()));
return;
if (mParts[PartIdx].first == Info)
{
DrawPreview(PartIdx);
mRequestedPreviews.removeOne(PartIdx);
break;
}
}
}
void lcPartSelectionListModel::DrawPreview(int InfoIndex)
{
/*
QRegion VisibleRegion = mListView->viewport()->visibleRegion();
int InfoIndex;
@@ -216,18 +249,18 @@ void lcPartSelectionListModel::DrawPreview()
if (mRequestedPreviews.isEmpty())
return;
InfoIndex = mRequestedPreviews.takeLast();
InfoIndex = mRequestedPreviews.takeFirst();
QRect ItemRect = mListView->visualRect(mListView->GetFilterModel()->mapFromSource(index(InfoIndex, 0)));
if (VisibleRegion.contains(ItemRect) || VisibleRegion.intersects(ItemRect))
break;
}
*/
View* View = gMainWindow->GetActiveView();
View->MakeCurrent();
lcContext* Context = View->mContext;
int Width = mIconSize;
int Height = mIconSize;
int Width = 128;
int Height = 128;
if (!Context->BeginRenderToTexture(Width, Height))
return;
@@ -235,15 +268,15 @@ void lcPartSelectionListModel::DrawPreview()
float Aspect = (float)Width / (float)Height;
Context->SetViewport(0, 0, Width, Height);
lcMatrix44 ProjectionMatrix = lcMatrix44Perspective(30.0f, Aspect, 1.0f, 2500.0f);
lcMatrix44 ProjectionMatrix = lcMatrix44Perspective(20.0f, Aspect, 1.0f, 12500.0f);
lcMatrix44 ViewMatrix;
Context->SetDefaultState();
Context->SetProjectionMatrix(ProjectionMatrix);
Context->SetProgram(LC_PROGRAM_SIMPLE);
lcPiecesLibrary* Library = lcGetPiecesLibrary();
PieceInfo* Info = mParts[InfoIndex].first;
Info->AddRef();
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -264,15 +297,12 @@ void lcPartSelectionListModel::DrawPreview()
Context->UnbindMesh(); // context remove
Info->Release();
Library->ReleasePieceInfo(Info);
mParts[InfoIndex].second = QPixmap::fromImage(Context->GetRenderToTextureImage(Width, Height));
mParts[InfoIndex].second = QPixmap::fromImage(Context->GetRenderToTextureImage(Width, Height)).scaled(mIconSize, mIconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
Context->EndRenderToTexture();
mLastDrawTime = QDateTime::currentDateTime();
QTimer::singleShot(100, this, SLOT(DrawPreview()));
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
emit dataChanged(index(InfoIndex, 0), index(InfoIndex, 0), QVector<int>() << Qt::DecorationRole);
#else
+5 -2
View File
@@ -43,6 +43,7 @@ class lcPartSelectionListModel : public QAbstractListModel
public:
lcPartSelectionListModel(QObject* Parent);
virtual ~lcPartSelectionListModel();
virtual int rowCount(const QModelIndex& Parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex& Index, int Role = Qt::DisplayRole) const;
@@ -66,13 +67,15 @@ public:
void SetIconSize(int Size);
protected slots:
void DrawPreview();
void PartLoaded(PieceInfo* Info);
protected:
void ClearRequests();
void DrawPreview(int InfoIndex);
lcPartSelectionListView* mListView;
QVector<QPair<PieceInfo*, QPixmap>> mParts;
QList<int> mRequestedPreviews;
QDateTime mLastDrawTime;
int mIconSize;
};
+2 -382
View File
@@ -19,7 +19,6 @@ lcZipFile::lcZipFile()
lcZipFile::~lcZipFile()
{
Flush();
delete mFile;
}
@@ -605,6 +604,8 @@ bool lcZipFile::ExtractFile(const char* FileName, lcMemFile& File, lcuint32 MaxL
bool lcZipFile::ExtractFile(int FileIndex, lcMemFile& File, lcuint32 MaxLength)
{
QMutexLocker Lock(&mMutex);
lcuint32 SizeVar;
lcuint64 OffsetLocalExtraField;
lcuint32 SizeLocalExtraField;
@@ -746,384 +747,3 @@ bool lcZipFile::ExtractFile(int FileIndex, lcMemFile& File, lcuint32 MaxLength)
return true;
}
bool lcZipFile::AddFile(const char* FileName, lcMemFile& File)
{
const size_t BufferSize = 16384;
char WriteBuffer[BufferSize];
z_stream Stream;
lcuint32 Crc32 = 0;
File.Seek(0, SEEK_SET);
Stream.zalloc = (alloc_func)0;
Stream.zfree = (free_func)0;
Stream.opaque = (voidpf)0;
if (deflateInit2(&Stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK)
return false;
lcMemFile* OutFile = new lcMemFile();
lcMemFile& CompressedFile = *OutFile;
Bytef* BufferIn = File.mBuffer;
int FlushMode;
do
{
uInt Read = lcMin(File.GetLength() - (BufferIn - File.mBuffer), BufferSize);
Stream.avail_in = Read;
Stream.next_in = BufferIn;
Crc32 = crc32(Crc32, BufferIn, Read);
BufferIn += Read;
FlushMode = (BufferIn >= File.mBuffer + File.GetLength()) ? Z_FINISH : Z_NO_FLUSH;
do
{
Stream.avail_out = BufferSize;
Stream.next_out = (Bytef*)WriteBuffer;
deflate(&Stream, FlushMode);
CompressedFile.WriteBuffer(WriteBuffer, BufferSize - Stream.avail_out);
} while (Stream.avail_out == 0);
} while (FlushMode != Z_FINISH);
deflateEnd(&Stream);
lcZipFileInfo& Info = mFiles.Add();
Info.version = 0;
if (CompressedFile.GetLength() >= 0xffffffffU || File.GetLength() >= 0xffffffffU)
Info.version_needed = 45;
else
Info.version_needed = 20;
Info.flag = 0;
Info.compression_method = Z_DEFLATED;
Info.crc = Crc32;
Info.compressed_size = CompressedFile.GetLength();
Info.uncompressed_size = File.GetLength();
Info.size_filename = (lcuint16)strlen(FileName);
Info.size_file_extra = 0;
Info.size_file_comment = 0;
Info.disk_num_start = 0;
Info.internal_fa = 0;
Info.external_fa = 0;
Info.offset_curfile = 0;
strncpy(Info.file_name, FileName, sizeof(Info.file_name));
time_t rawtime;
struct tm* timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
Info.tmu_date.tm_sec = timeinfo->tm_sec;
Info.tmu_date.tm_min = timeinfo->tm_min;
Info.tmu_date.tm_hour = timeinfo->tm_hour;
Info.tmu_date.tm_mday = timeinfo->tm_mday;
Info.tmu_date.tm_mon = timeinfo->tm_mon ;
Info.tmu_date.tm_year = timeinfo->tm_year - 80;
Info.dosDate = (((timeinfo->tm_mday) + (32 * (timeinfo->tm_mon + 1)) + (512 * timeinfo->tm_year)) << 16) | ((timeinfo->tm_sec / 2) + (32 * timeinfo->tm_min) + (2048 * (uLong)timeinfo->tm_hour));
Info.write_buffer = OutFile;
Info.deleted = false;
mModified = true;
return true;
}
bool lcZipFile::DeleteFile(const char* FileName)
{
for (int FileIdx = 0; FileIdx < mFiles.GetSize(); FileIdx++)
{
lcZipFileInfo& FileInfo = mFiles[FileIdx];
if (!stricmp(FileInfo.file_name, FileName))
{
FileInfo.deleted = true;
mModified = true;
return true;
}
}
return false;
}
void lcZipFile::Flush()
{
if (!mFile || !mModified)
return;
lcMemFile MemFile;
lcuint64 NumFiles = 0;
mFile->Seek(0, SEEK_SET);
if (mBytesBeforeZipFile)
{
MemFile.GrowFile((size_t)mBytesBeforeZipFile);
mFile->ReadBuffer(MemFile.mBuffer, (long)mBytesBeforeZipFile);
MemFile.Seek((long)mBytesBeforeZipFile, SEEK_CUR);
}
for (int FileIdx = 0; FileIdx < mFiles.GetSize(); FileIdx++)
{
lcZipFileInfo& FileInfo = mFiles[FileIdx];
if (FileInfo.deleted)
continue;
lcuint32 SizeVar;
lcuint64 OffsetLocalExtraField;
lcuint32 SizeLocalExtraField;
CheckFileCoherencyHeader(FileIdx, &SizeVar, &OffsetLocalExtraField, &SizeLocalExtraField);
NumFiles++;
lcuint64 PosInZipfile = FileInfo.offset_curfile + 0x1e + SizeVar;
mFile->Seek((long)(PosInZipfile + mBytesBeforeZipFile), SEEK_SET);
FileInfo.offset_curfile = MemFile.GetPosition();
if (FileInfo.offset_curfile >= 0xffffffffU)
FileInfo.version_needed = 45;
MemFile.WriteU32(0x04034b50);
MemFile.WriteU16(FileInfo.version_needed);
MemFile.WriteU16(FileInfo.flag);
MemFile.WriteU16(FileInfo.compression_method);
MemFile.WriteU32(FileInfo.dosDate);
MemFile.WriteU32(FileInfo.crc);
if (FileInfo.compressed_size >= 0xffffffffU)
MemFile.WriteU32(0xffffffffU);
else
MemFile.WriteU32((lcuint32)FileInfo.compressed_size);
if (FileInfo.uncompressed_size >= 0xffffffffU)
MemFile.WriteU32(0xffffffffU);
else
MemFile.WriteU32((lcuint32)FileInfo.uncompressed_size);
MemFile.WriteU16(FileInfo.size_filename);
MemFile.WriteU16(FileInfo.size_file_extra);
MemFile.WriteBuffer(FileInfo.file_name, FileInfo.size_filename);
if (FileInfo.write_buffer)
{
MemFile.WriteBuffer(FileInfo.write_buffer->mBuffer, FileInfo.write_buffer->GetLength());
delete FileInfo.write_buffer;
FileInfo.write_buffer = NULL;
}
else
{
MemFile.GrowFile((size_t)(MemFile.GetPosition() + FileInfo.compressed_size));
mFile->ReadBuffer(MemFile.mBuffer + MemFile.GetPosition(), (long)FileInfo.compressed_size);
MemFile.Seek((long)FileInfo.compressed_size, SEEK_CUR);
}
}
lcuint64 CentralDirPos = MemFile.GetPosition();
for (int FileIdx = 0; FileIdx < mFiles.GetSize(); FileIdx++)
{
lcZipFileInfo& FileInfo = mFiles[FileIdx];
if (FileInfo.deleted)
continue;
MemFile.WriteU32(0x02014b50);
MemFile.WriteU16(FileInfo.version);
MemFile.WriteU16(FileInfo.version_needed);
MemFile.WriteU16(FileInfo.flag);
MemFile.WriteU16(FileInfo.compression_method);
MemFile.WriteU32(FileInfo.dosDate);
MemFile.WriteU32(FileInfo.crc);
if (FileInfo.compressed_size >= 0xffffffffU)
MemFile.WriteU32(0xffffffffU);
else
MemFile.WriteU32((lcuint32)FileInfo.compressed_size);
if (FileInfo.uncompressed_size >= 0xffffffffU)
MemFile.WriteU32(0xffffffffU);
else
MemFile.WriteU32((lcuint32)FileInfo.uncompressed_size);
MemFile.WriteU16(FileInfo.size_filename);
MemFile.WriteU16(FileInfo.size_file_extra);
MemFile.WriteU16(FileInfo.size_file_comment);
MemFile.WriteU16(FileInfo.disk_num_start);
MemFile.WriteU16(FileInfo.internal_fa);
MemFile.WriteU32(FileInfo.external_fa);
if (FileInfo.offset_curfile >= 0xffffffffU)
MemFile.WriteU32(0xffffffffU);
else
MemFile.WriteU32((lcuint32)(FileInfo.offset_curfile - mBytesBeforeZipFile));
MemFile.WriteBuffer(FileInfo.file_name, FileInfo.size_filename);
}
lcuint64 CentralDirEnd = MemFile.GetPosition();
if (CentralDirPos - mBytesBeforeZipFile >= 0xffffffffU)
{
MemFile.WriteU32(0x6064b50);
MemFile.WriteU64(44);
MemFile.WriteU16(45);
MemFile.WriteU16(45);
MemFile.WriteU32(0);
MemFile.WriteU32(0);
MemFile.WriteU64(NumFiles);
MemFile.WriteU64(NumFiles);
MemFile.WriteU64(CentralDirEnd - CentralDirPos);
MemFile.WriteU64(CentralDirPos - mBytesBeforeZipFile);
MemFile.WriteU32(0x7064b50);
MemFile.WriteU32(0);
MemFile.WriteU64(CentralDirEnd - mBytesBeforeZipFile);
MemFile.WriteU32(1);
}
MemFile.WriteU32(0x06054b50);
MemFile.WriteU16(0);
MemFile.WriteU16(0);
if (NumFiles >= 0xffff)
MemFile.WriteU16(0xffff);
else
MemFile.WriteU16((lcuint16)NumFiles);
if (NumFiles >= 0xffff)
MemFile.WriteU16(0xffff);
else
MemFile.WriteU16((lcuint16)NumFiles);
MemFile.WriteU32((lcuint32)(CentralDirEnd - CentralDirPos));
if (CentralDirPos - mBytesBeforeZipFile >= 0xffffffffU)
MemFile.WriteU32(0xffffffffU);
else
MemFile.WriteU32((lcuint32)(CentralDirPos - mBytesBeforeZipFile));
MemFile.WriteU16(0);
mFile->CopyFrom(MemFile);
/*
lcuint64 CurrentOffset = mCentralDirOffset + mBytesBeforeZipFile;
mFile->Seek((long)CurrentOffset, SEEK_SET);
void* CentralDir = malloc((long)mCentralDirSize);
mFile->ReadBuffer(CentralDir, (long)mCentralDirSize);
mFile->Seek((long)CurrentOffset, SEEK_SET);
for (int FileIdx = FirstFileAdded; FileIdx < mFiles.GetSize(); FileIdx++)
{
lcZipFileInfo& FileInfo = mFiles[FileIdx];
FileInfo.offset_curfile = CurrentOffset;
if (FileInfo.offset_curfile >= 0xffffffffU)
FileInfo.version_needed = 45;
mFile->WriteU32(0x04034b50);
mFile->WriteU16(FileInfo.version_needed);
mFile->WriteU16(FileInfo.flag);
mFile->WriteU16(FileInfo.compression_method);
mFile->WriteU32(FileInfo.dosDate);
mFile->WriteU32(FileInfo.crc);
if (FileInfo.compressed_size >= 0xffffffffU)
mFile->WriteU32(0xffffffffU);
else
mFile->WriteU32((lcuint32)FileInfo.compressed_size);
if (FileInfo.uncompressed_size >= 0xffffffffU)
mFile->WriteU32(0xffffffffU);
else
mFile->WriteU32((lcuint32)FileInfo.uncompressed_size);
mFile->WriteU16(FileInfo.size_filename);
mFile->WriteU16(FileInfo.size_file_extra);
mFile->WriteBuffer(FileInfo.file_name, FileInfo.size_filename);
mFile->WriteBuffer(FileInfo.write_buffer->mBuffer, FileInfo.write_buffer->GetLength());
delete FileInfo.write_buffer;
FileInfo.write_buffer = NULL;
CurrentOffset = mFile->GetPosition();
}
lcuint64 CentralDirPos = mFile->GetPosition();
mFile->WriteBuffer(CentralDir, (long)mCentralDirSize);
free(CentralDir);
for (int FileIdx = FirstFileAdded; FileIdx < mFiles.GetSize(); FileIdx++)
{
lcZipFileInfo& FileInfo = mFiles[FileIdx];
mFile->WriteU32(0x02014b50);
mFile->WriteU16(FileInfo.version);
mFile->WriteU16(FileInfo.version_needed);
mFile->WriteU16(FileInfo.flag);
mFile->WriteU16(FileInfo.compression_method);
mFile->WriteU32(FileInfo.dosDate);
mFile->WriteU32(FileInfo.crc);
if (FileInfo.compressed_size >= 0xffffffffU)
mFile->WriteU32(0xffffffffU);
else
mFile->WriteU32((lcuint32)FileInfo.compressed_size);
if (FileInfo.uncompressed_size >= 0xffffffffU)
mFile->WriteU32(0xffffffffU);
else
mFile->WriteU32((lcuint32)FileInfo.uncompressed_size);
mFile->WriteU16(FileInfo.size_filename);
mFile->WriteU16(FileInfo.size_file_extra);
mFile->WriteU16(FileInfo.size_file_comment);
mFile->WriteU16(FileInfo.disk_num_start);
mFile->WriteU16(FileInfo.internal_fa);
mFile->WriteU32(FileInfo.external_fa);
if (FileInfo.offset_curfile >= 0xffffffffU)
mFile->WriteU32(0xffffffffU);
else
mFile->WriteU32((lcuint32)(FileInfo.offset_curfile - mBytesBeforeZipFile));
mFile->WriteBuffer(FileInfo.file_name, FileInfo.size_filename);
}
lcuint64 CentralDirEnd = mFile->GetPosition();
if (CentralDirPos - mBytesBeforeZipFile >= 0xffffffffU)
{
mFile->WriteU32(0x6064b50);
mFile->WriteU64(44);
mFile->WriteU16(45);
mFile->WriteU16(45);
mFile->WriteU32(0);
mFile->WriteU32(0);
mFile->WriteU64(mFiles.GetSize());
mFile->WriteU64(mFiles.GetSize());
mFile->WriteU64(CentralDirEnd - CentralDirPos);
mFile->WriteU64(CentralDirPos - mBytesBeforeZipFile);
mFile->WriteU32(0x7064b50);
mFile->WriteU32(0);
mFile->WriteU64(CentralDirEnd - mBytesBeforeZipFile);
mFile->WriteU32(1);
}
mFile->WriteU32(0x06054b50);
mFile->WriteU16(0);
mFile->WriteU16(0);
if (mFiles.GetSize() >= 0xffff)
mFile->WriteU16(0xffff);
else
mFile->WriteU16(mFiles.GetSize());
if (mFiles.GetSize() >= 0xffff)
mFile->WriteU16(0xffff);
else
mFile->WriteU16(mFiles.GetSize());
mFile->WriteU32((lcuint32)(CentralDirEnd - CentralDirPos));
if (CentralDirPos - mBytesBeforeZipFile >= 0xffffffffU)
mFile->WriteU32(0xffffffffU);
else
mFile->WriteU32((lcuint32)(CentralDirPos - mBytesBeforeZipFile));
mFile->WriteU16(0);
*/
}
+1 -3
View File
@@ -59,19 +59,17 @@ public:
bool ExtractFile(int FileIndex, lcMemFile& File, lcuint32 MaxLength = 0xffffffff);
bool ExtractFile(const char* FileName, lcMemFile& File, lcuint32 MaxLength = 0xffffffff);
bool AddFile(const char* FileName, lcMemFile& File);
bool DeleteFile(const char* FileName);
lcArray<lcZipFileInfo> mFiles;
protected:
bool Open();
void Flush();
bool ReadCentralDir();
lcuint64 SearchCentralDir();
lcuint64 SearchCentralDir64();
bool CheckFileCoherencyHeader(int FileIndex, lcuint32* SizeVar, lcuint64* OffsetLocalExtraField, lcuint32* SizeLocalExtraField);
QMutex mMutex;
lcFile* mFile;
bool mModified;
+10 -5
View File
@@ -58,27 +58,31 @@ void MinifigWizard::OnInitialUpdate()
const int ColorCodes[LC_MFW_NUMITEMS] = { 4, 7, 14, 7, 1, 0, 7, 4, 4, 14, 14, 7, 7, 0, 0, 7, 7 };
const char* Pieces[LC_MFW_NUMITEMS] = { "3624", "None", "3626BP01", "None", "973", "3815", "None", "3819", "3818", "3820", "3820", "None", "None", "3817", "3816", "None", "None" };
lcPiecesLibrary* Library = lcGetPiecesLibrary();
for (int i = 0; i < LC_MFW_NUMITEMS; i++)
{
mMinifig.Colors[i] = lcGetColorIndex(ColorCodes[i]);
PieceInfo* Info = lcGetPiecesLibrary()->FindPiece(Pieces[i], NULL, false, false);
PieceInfo* Info = Library->FindPiece(Pieces[i], NULL, false, false);
if (Info)
{
mMinifig.Parts[i] = Info;
Info->AddRef();
Library->LoadPieceInfo(Info, false, true);
}
}
Library->WaitForLoadQueue();
Calculate();
}
MinifigWizard::~MinifigWizard()
{
lcPiecesLibrary* Library = lcGetPiecesLibrary();
for (int i = 0; i < LC_MFW_NUMITEMS; i++)
if (mMinifig.Parts[i])
mMinifig.Parts[i]->Release();
Library->ReleasePieceInfo(mMinifig.Parts[i]);
}
void MinifigWizard::ParseSettings(lcFile& Settings)
@@ -547,15 +551,16 @@ int MinifigWizard::GetSelectionIndex(int Type) const
void MinifigWizard::SetSelectionIndex(int Type, int Index)
{
lcPiecesLibrary* Library = lcGetPiecesLibrary();
MakeCurrent();
if (mMinifig.Parts[Type])
mMinifig.Parts[Type]->Release();
Library->ReleasePieceInfo(mMinifig.Parts[Type]);
mMinifig.Parts[Type] = mSettings[Type][Index].Info;
if (mMinifig.Parts[Type])
mMinifig.Parts[Type]->AddRef();
Library->LoadPieceInfo(mMinifig.Parts[Type], true, true);
Calculate();
}
+10 -5
View File
@@ -20,7 +20,7 @@ lcPiece::lcPiece(PieceInfo* Info)
: lcObject(LC_OBJECT_PIECE)
{
mMesh = NULL;
SetPieceInfo(Info);
SetPieceInfo(Info, true);
mState = 0;
mColorIndex = gDefaultColor;
mColorCode = 16;
@@ -37,16 +37,21 @@ lcPiece::lcPiece(PieceInfo* Info)
lcPiece::~lcPiece()
{
if (mPieceInfo)
mPieceInfo->Release();
{
lcPiecesLibrary* Library = lcGetPiecesLibrary();
Library->ReleasePieceInfo(mPieceInfo);
}
delete mMesh;
}
void lcPiece::SetPieceInfo(PieceInfo* Info)
void lcPiece::SetPieceInfo(PieceInfo* Info, bool Wait)
{
lcPiecesLibrary* Library = lcGetPiecesLibrary();
mPieceInfo = Info;
if (mPieceInfo)
mPieceInfo->AddRef();
Library->LoadPieceInfo(mPieceInfo, Wait, true);
mControlPoints.RemoveAll();
delete mMesh;
@@ -266,7 +271,7 @@ bool lcPiece::FileLoad(lcFile& file)
file.ReadBuffer(name, LC_PIECE_NAME_LEN);
PieceInfo* pInfo = lcGetPiecesLibrary()->FindPiece(name, NULL, true, false);
SetPieceInfo(pInfo);
SetPieceInfo(pInfo, true);
// 11 (0.77)
if (version < 11)
+1 -1
View File
@@ -388,7 +388,7 @@ public:
void Initialize(const lcMatrix44& WorldMatrix, lcStep Step);
const lcBoundingBox& GetBoundingBox() const;
void CompareBoundingBox(lcVector3& Min, lcVector3& Max) const;
void SetPieceInfo(PieceInfo* Info);
void SetPieceInfo(PieceInfo* Info, bool Wait);
bool FileLoad(lcFile& file);
void UpdatePosition(lcStep Step);
+25 -19
View File
@@ -18,7 +18,7 @@ PieceInfo::PieceInfo()
mZipFileType = LC_NUM_ZIPFILES;
mZipFileIndex = -1;
mFlags = 0;
mLoaded = false;
mState = LC_PIECEINFO_UNLOADED;
mRefCount = 0;
mMesh = NULL;
mModel = NULL;
@@ -30,7 +30,7 @@ PieceInfo::~PieceInfo()
{
delete mSynthInfo;
if (mLoaded)
if (mState == LC_PIECEINFO_LOADED)
Unload();
}
@@ -42,6 +42,12 @@ QString PieceInfo::GetSaveID() const
return QString::fromLatin1(m_strName) + QLatin1String(".DAT");
}
void PieceInfo::SetMesh(lcMesh* Mesh)
{
mBoundingBox = Mesh->mBoundingBox;
mMesh = Mesh;
}
void PieceInfo::SetPlaceholder()
{
mBoundingBox.Min = lcVector3(-10.0f, -10.0f, -24.0f);
@@ -100,7 +106,7 @@ void PieceInfo::SetProject(Project* Project, const char* PieceName)
{
mFlags = LC_PIECE_PROJECT;
mProject = Project;
mLoaded = true;
mState = LC_PIECEINFO_LOADED;
}
strncpy(m_strName, PieceName, sizeof(m_strName));
@@ -134,25 +140,25 @@ void PieceInfo::CreatePlaceholder(const char* Name)
void PieceInfo::Load()
{
mLoaded = true;
if ((mFlags & (LC_PIECE_MODEL | LC_PIECE_PROJECT)) == 0)
{
mState = LC_PIECEINFO_LOADING; // todo: mutex lock when changing load state
if (mFlags & (LC_PIECE_MODEL | LC_PIECE_PROJECT))
return;
else if (mFlags & LC_PIECE_PLACEHOLDER)
{
if (lcGetPiecesLibrary()->LoadPiece(this))
mFlags &= ~LC_PIECE_PLACEHOLDER;
else
if (mFlags & LC_PIECE_PLACEHOLDER)
{
mFlags |= LC_PIECE_HAS_DEFAULT | LC_PIECE_HAS_LINES;
mBoundingBox = gPlaceholderMesh->mBoundingBox;
if (lcGetPiecesLibrary()->LoadPieceData(this))
mFlags &= ~LC_PIECE_PLACEHOLDER;
else
{
mFlags |= LC_PIECE_HAS_DEFAULT | LC_PIECE_HAS_LINES;
mBoundingBox = gPlaceholderMesh->mBoundingBox;
}
}
else
lcGetPiecesLibrary()->LoadPieceData(this);
}
else
{
lcGetPiecesLibrary()->LoadPiece(this);
mBoundingBox = mMesh->mBoundingBox;
}
mState = LC_PIECEINFO_LOADED;
}
void PieceInfo::Unload()
@@ -174,7 +180,7 @@ void PieceInfo::Unload()
mMesh = NULL;
}
mLoaded = false;
mState = LC_PIECEINFO_UNLOADED;
mModel = NULL;
if (IsModel())
+18 -25
View File
@@ -15,6 +15,13 @@
#define LC_PIECE_NAME_LEN 256
enum lcPieceInfoState
{
LC_PIECEINFO_UNLOADED,
LC_PIECEINFO_LOADING,
LC_PIECEINFO_LOADED
};
class lcSynthInfo;
class PieceInfo
@@ -56,36 +63,23 @@ public:
return mModel;
}
void SetMesh(lcMesh* Mesh)
{
mMesh = Mesh;
}
void SetMesh(lcMesh* Mesh);
void AddRef()
int AddRef()
{
mRefCount++;
if (!mLoaded)
Load();
return mRefCount;
}
void Release()
int Release()
{
mRefCount--;
if (!mRefCount)
Unload();
return mRefCount;
}
void UnloadIfUnused()
int GetRefCount() const
{
if (!mRefCount && mLoaded)
Unload();
}
bool IsLoaded() const
{
return mLoaded;
return mRefCount;
}
bool IsPlaceholder() const
@@ -153,25 +147,24 @@ public:
void GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcArray<lcModelPartsEntry>& ModelParts) const;
void UpdateBoundingBox(lcArray<lcModel*>& UpdatedModels);
void Load();
void Unload();
public:
// Attributes
char m_strName[LC_PIECE_NAME_LEN];
char m_strDescription[128];
int mZipFileType;
int mZipFileIndex;
lcuint32 mFlags;
lcPieceInfoState mState;
protected:
bool mLoaded;
int mRefCount;
lcModel* mModel;
Project* mProject;
lcMesh* mMesh;
lcBoundingBox mBoundingBox;
lcSynthInfo* mSynthInfo;
void Load();
void Unload();
};
#endif // _PIECEINF_H_