leocad/common/lc_library.cpp

2026 lines
51 KiB
C++
Raw Normal View History

2012-09-20 02:53:12 +02:00
#include "lc_global.h"
#include "lc_library.h"
2012-09-29 02:16:43 +02:00
#include "lc_zipfile.h"
#include "lc_file.h"
#include "pieceinf.h"
#include "lc_colors.h"
2012-10-12 01:55:55 +02:00
#include "lc_texture.h"
2012-10-02 03:23:44 +02:00
#include "system.h"
2012-10-06 01:09:38 +02:00
#include <sys/types.h>
#include <sys/stat.h>
#define LC_LIBRARY_CACHE_VERSION 0x0100
#define LC_LIBRARY_CACHE_ARCHIVE 0x0001
#define LC_LIBRARY_CACHE_DIRECTORY 0x0002
2012-09-20 02:53:12 +02:00
lcPiecesLibrary::lcPiecesLibrary()
{
2012-11-29 05:51:51 +01:00
mNumOfficialPieces = 0;
2012-09-29 02:16:43 +02:00
mZipFile = NULL;
2012-11-09 01:07:53 +01:00
mCacheFile = NULL;
2012-11-08 05:05:52 +01:00
mSaveCache = false;
2012-09-20 02:53:12 +02:00
}
lcPiecesLibrary::~lcPiecesLibrary()
2012-10-12 01:55:55 +02:00
{
Unload();
}
void lcPiecesLibrary::Unload()
2012-09-20 02:53:12 +02:00
{
2012-11-09 01:07:53 +01:00
SaveCacheFile();
2012-11-08 05:05:52 +01:00
2012-09-29 02:16:43 +02:00
for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++)
delete mPieces[PieceIdx];
2012-10-12 01:55:55 +02:00
mPieces.RemoveAll();
for (int PrimitiveIdx = 0; PrimitiveIdx < mPrimitives.GetSize(); PrimitiveIdx++)
delete mPrimitives[PrimitiveIdx];
mPrimitives.RemoveAll();
for (int TextureIdx = 0; TextureIdx < mTextures.GetSize(); TextureIdx++)
delete mTextures[TextureIdx];
mTextures.RemoveAll();
2012-09-29 02:16:43 +02:00
2012-11-29 05:51:51 +01:00
mNumOfficialPieces = 0;
2012-09-29 02:16:43 +02:00
delete mZipFile;
2012-10-12 01:55:55 +02:00
mZipFile = NULL;
2012-09-29 02:16:43 +02:00
}
2012-10-02 03:23:44 +02:00
PieceInfo* lcPiecesLibrary::FindPiece(const char* PieceName, bool CreatePlaceholderIfMissing)
{
for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++)
if (!strcmp(PieceName, mPieces[PieceIdx]->m_strName))
return mPieces[PieceIdx];
if (CreatePlaceholderIfMissing)
return CreatePlaceholder(PieceName);
return NULL;
}
PieceInfo* lcPiecesLibrary::CreatePlaceholder(const char* PieceName)
{
PieceInfo* Info = new PieceInfo(-1);
2012-10-02 03:23:44 +02:00
Info->CreatePlaceholder(PieceName);
mPieces.Add(Info);
return Info;
}
2012-10-12 01:55:55 +02:00
lcTexture* lcPiecesLibrary::FindTexture(const char* TextureName)
{
for (int TextureIdx = 0; TextureIdx < mTextures.GetSize(); TextureIdx++)
if (!strcmp(TextureName, mTextures[TextureIdx]->mName))
return mTextures[TextureIdx];
return NULL;
}
bool lcPiecesLibrary::Load(const char* LibraryPath, const char* CachePath)
2012-10-02 03:23:44 +02:00
{
if (OpenArchive(LibraryPath, CachePath))
2012-10-04 00:38:33 +02:00
{
lcMemFile ColorFile;
if (!mZipFile->ExtractFile("ldraw/ldconfig.ldr", ColorFile) || !lcLoadColorFile(ColorFile))
lcLoadDefaultColors();
strcpy(mLibraryPath, LibraryPath);
char* Slash = lcMax(strrchr(mLibraryPath, '/'), strrchr(mLibraryPath, '\\'));
if (*Slash)
*(Slash + 1) = 0;
2012-10-04 00:38:33 +02:00
}
else
2012-10-04 00:38:33 +02:00
{
strcpy(mLibraryPath, LibraryPath);
2012-10-04 00:38:33 +02:00
int i = strlen(mLibraryPath) - 1;
if ((mLibraryPath[i] != '\\') && (mLibraryPath[i] != '/'))
strcat(mLibraryPath, "/");
2012-10-04 00:38:33 +02:00
if (OpenDirectory(mLibraryPath))
{
char FileName[LC_MAXPATH];
lcDiskFile ColorFile;
sprintf(FileName, "%sldconfig.ldr", mLibraryPath);
if (!ColorFile.Open(FileName, "rt") || !lcLoadColorFile(ColorFile))
lcLoadDefaultColors();
}
else
return false;
2012-10-04 00:38:33 +02:00
}
2012-10-02 03:23:44 +02:00
const char* FileName = Sys_ProfileLoadString("Settings", "Categories", "");
if (!FileName[0] || !LoadCategories(FileName))
2012-10-02 03:23:44 +02:00
ResetCategories();
SystemUpdateCategories(false);
return true;
}
bool lcPiecesLibrary::OpenArchive(const char* FileName, const char* CachePath)
2012-09-29 02:16:43 +02:00
{
2012-10-17 00:24:43 +02:00
Unload();
2012-09-29 02:16:43 +02:00
mZipFile = new lcZipFile();
2012-10-05 21:11:37 +02:00
if (!mZipFile->OpenRead(FileName))
2012-09-29 02:16:43 +02:00
{
delete mZipFile;
mZipFile = NULL;
return false;
}
2012-11-08 05:05:52 +01:00
strcpy(mLibraryFileName, FileName);
2012-09-29 02:16:43 +02:00
for (int FileIdx = 0; FileIdx < mZipFile->mFiles.GetSize(); FileIdx++)
{
lcZipFileInfo& FileInfo = mZipFile->mFiles[FileIdx];
char Name[LC_PIECE_NAME_LEN];
const char* Src = FileInfo.file_name;
char* Dst = Name;
while (*Src && Dst - Name < LC_PIECE_NAME_LEN)
{
if (*Src >= 'a' && *Src <= 'z')
*Dst = *Src + 'A' - 'a';
else if (*Src == '\\')
*Dst = '/';
else
*Dst = *Src;
Src++;
Dst++;
}
if (Dst - Name <= 4)
continue;
Dst -= 4;
if (memcmp(Dst, ".DAT", 4))
2012-10-12 01:55:55 +02:00
{
if (!memcmp(Dst, ".PNG", 4) && !memcmp(Name, "LDRAW/PARTS/TEXTURES/", 21))
{
lcTexture* Texture = new lcTexture();
mTextures.Add(Texture);
strncpy(Texture->mName, Name + 21, sizeof(Texture->mName));
Texture->mName[sizeof(Texture->mName) - 1] = 0;
}
2012-09-29 02:16:43 +02:00
continue;
2012-10-12 01:55:55 +02:00
}
2012-09-29 02:16:43 +02:00
*Dst = 0;
if (memcmp(Name, "LDRAW/", 6))
continue;
if (!memcmp(Name + 6, "PARTS/", 6))
{
if (memcmp(Name + 12, "S/", 2))
{
PieceInfo* Info = new PieceInfo(FileIdx);
2012-09-29 02:16:43 +02:00
mPieces.Add(Info);
strncpy(Info->m_strName, Name + 12, sizeof(Info->m_strName));
Info->m_strName[sizeof(Info->m_strName) - 1] = 0;
}
else
{
lcLibraryPrimitive* Prim = new lcLibraryPrimitive(Name + 12, FileIdx, false, true);
2012-09-29 02:16:43 +02:00
mPrimitives.Add(Prim);
}
}
else if (!memcmp(Name + 6, "P/", 2))
{
2012-10-05 21:11:37 +02:00
lcLibraryPrimitive* Prim = new lcLibraryPrimitive(Name + 8, FileIdx, (memcmp(Name + 8, "STU", 3) == 0), false);
2012-09-29 02:16:43 +02:00
mPrimitives.Add(Prim);
}
}
2012-10-06 01:09:38 +02:00
bool CacheValid = false;
2012-10-12 01:55:55 +02:00
struct stat LibraryStat;
2012-10-06 01:09:38 +02:00
strcpy(mCacheFileName, CachePath);
2012-11-08 05:05:52 +01:00
mCacheFileModifiedTime = 0;
if (CachePath[0])
2012-10-06 01:09:38 +02:00
strcat(mCacheFileName, "library.cache");
2012-09-29 02:16:43 +02:00
2012-10-06 01:09:38 +02:00
if (stat(FileName, &LibraryStat) == 0)
2012-09-29 02:16:43 +02:00
{
2012-10-06 01:09:38 +02:00
lcZipFile CacheFile;
2012-09-29 02:16:43 +02:00
2012-10-06 01:09:38 +02:00
if (CacheFile.OpenRead(mCacheFileName))
{
lcMemFile VersionFile;
2012-09-29 02:16:43 +02:00
2012-10-06 01:09:38 +02:00
if (CacheFile.ExtractFile("version", VersionFile))
{
lcuint32 CacheVersion;
lcuint32 CacheFlags;
lcuint64 LibrarySize;
lcuint64 LibraryModified;
if (VersionFile.ReadU32(&CacheVersion, 1) && VersionFile.ReadU32(&CacheFlags, 1) &&
VersionFile.ReadU64(&LibrarySize, 1) && VersionFile.ReadU64(&LibraryModified, 1))
{
if (CacheVersion == LC_LIBRARY_CACHE_VERSION && CacheFlags == LC_LIBRARY_CACHE_ARCHIVE &&
2012-10-17 00:24:43 +02:00
LibrarySize == (lcuint64)LibraryStat.st_size && LibraryModified == (lcuint64)LibraryStat.st_mtime)
2012-10-06 01:09:38 +02:00
CacheValid = true;
}
}
}
2012-09-29 02:16:43 +02:00
2012-10-06 01:09:38 +02:00
if (CacheValid)
2012-11-08 05:05:52 +01:00
CacheValid = LoadCacheIndex(CacheFile);
}
2012-10-06 01:09:38 +02:00
2012-11-08 05:05:52 +01:00
if (CacheValid)
{
struct stat CacheStat;
2012-10-06 01:09:38 +02:00
2012-11-08 05:05:52 +01:00
if (stat(mCacheFileName, &CacheStat) == 0)
mCacheFileModifiedTime = CacheStat.st_mtime;
2012-10-06 01:09:38 +02:00
}
2012-11-08 05:05:52 +01:00
else
2012-10-06 01:09:38 +02:00
{
lcMemFile PieceFile;
2012-11-08 05:05:52 +01:00
mSaveCache = true;
2012-10-06 01:09:38 +02:00
for (int PieceInfoIndex = 0; PieceInfoIndex < mPieces.GetSize(); PieceInfoIndex++)
{
PieceInfo* Info = mPieces[PieceInfoIndex];
mZipFile->ExtractFile(Info->mZipFileIndex, PieceFile, 256);
PieceFile.Seek(0, SEEK_END);
PieceFile.WriteU8(0);
char* Src = (char*)PieceFile.mBuffer + 2;
char* Dst = Info->m_strDescription;
for (;;)
{
2012-10-17 00:24:43 +02:00
if (*Src != '\r' && *Src != '\n' && *Src && Dst - Info->m_strDescription < (int)sizeof(Info->m_strDescription) - 1)
2012-10-06 01:09:38 +02:00
{
*Dst++ = *Src++;
continue;
}
*Dst = 0;
break;
}
}
2012-09-29 02:16:43 +02:00
}
return true;
}
bool lcPiecesLibrary::OpenDirectory(const char* Path)
2012-09-29 02:16:43 +02:00
{
2012-10-17 00:24:43 +02:00
Unload();
char FileName[LC_MAXPATH];
ObjArray<String> FileList;
strcpy(FileName, Path);
strcat(FileName, "parts/");
int PathLength = strlen(FileName);
Sys_GetFileList(FileName, FileList);
mPieces.Expand(FileList.GetSize());
for (int FileIdx = 0; FileIdx < FileList.GetSize(); FileIdx++)
2012-09-29 02:16:43 +02:00
{
char Name[LC_PIECE_NAME_LEN];
const char* Src = (const char*)FileList[FileIdx] + PathLength;
char* Dst = Name;
2012-09-29 02:16:43 +02:00
2012-10-17 00:24:43 +02:00
while (*Src && Dst - Name < (int)sizeof(Name))
{
if (*Src >= 'a' && *Src <= 'z')
*Dst = *Src + 'A' - 'a';
else if (*Src == '\\')
*Dst = '/';
else
*Dst = *Src;
Src++;
Dst++;
}
if (Dst - Name <= 4)
continue;
Dst -= 4;
if (memcmp(Dst, ".DAT", 4))
continue;
*Dst = 0;
lcDiskFile PieceFile;
if (!PieceFile.Open(FileList[FileIdx], "rt"))
continue;
char Line[1024];
if (!PieceFile.ReadLine(Line, sizeof(Line)))
continue;
PieceInfo* Info = new PieceInfo(-1);
mPieces.Add(Info);
Src = (char*)Line + 2;
Dst = Info->m_strDescription;
for (;;)
{
2012-10-17 00:24:43 +02:00
if (*Src != '\r' && *Src != '\n' && *Src && Dst - Info->m_strDescription < (int)sizeof(Info->m_strDescription) - 1)
{
*Dst++ = *Src++;
continue;
}
*Dst = 0;
break;
}
strncpy(Info->m_strName, Name, sizeof(Info->m_strName));
Info->m_strName[sizeof(Info->m_strName) - 1] = 0;
2012-09-29 02:16:43 +02:00
}
if (!mPieces.GetSize())
return false;
const char* PrimitiveDirectories[] = { "p/", "p/48/", "parts/s/" };
bool SubFileDirectories[] = { false, false, true };
2012-10-17 00:24:43 +02:00
for (int DirectoryIdx = 0; DirectoryIdx < (int)(sizeof(PrimitiveDirectories) / sizeof(PrimitiveDirectories[0])); DirectoryIdx++)
{
strcpy(FileName, Path);
PathLength = strlen(FileName);
strcat(FileName, PrimitiveDirectories[DirectoryIdx]);
PathLength += strchr(PrimitiveDirectories[DirectoryIdx], '/') - PrimitiveDirectories[DirectoryIdx] + 1;
Sys_GetFileList(FileName, FileList);
for (int FileIdx = 0; FileIdx < FileList.GetSize(); FileIdx++)
{
char Name[LC_PIECE_NAME_LEN];
const char* Src = (const char*)FileList[FileIdx] + PathLength;
char* Dst = Name;
2012-10-17 00:24:43 +02:00
while (*Src && Dst - Name < (int)sizeof(Name))
{
if (*Src >= 'a' && *Src <= 'z')
*Dst = *Src + 'A' - 'a';
else if (*Src == '\\')
*Dst = '/';
else
*Dst = *Src;
Src++;
Dst++;
}
if (Dst - Name <= 4)
continue;
Dst -= 4;
if (memcmp(Dst, ".DAT", 4))
continue;
*Dst = 0;
bool SubFile = SubFileDirectories[DirectoryIdx];
lcLibraryPrimitive* Prim = new lcLibraryPrimitive(Name, 0, !SubFile && (memcmp(Name, "STU", 3) == 0), SubFile);
mPrimitives.Add(Prim);
}
}
2012-10-12 01:55:55 +02:00
strcpy(FileName, Path);
strcat(FileName, "parts/textures/");
PathLength = strlen(FileName);
Sys_GetFileList(FileName, FileList);
mTextures.Expand(FileList.GetSize());
for (int FileIdx = 0; FileIdx < FileList.GetSize(); FileIdx++)
{
char Name[LC_MAXPATH];
const char* Src = (const char*)FileList[FileIdx] + PathLength;
char* Dst = Name;
2012-10-17 00:24:43 +02:00
while (*Src && Dst - Name < (int)sizeof(Name))
2012-10-12 01:55:55 +02:00
{
if (*Src >= 'a' && *Src <= 'z')
*Dst = *Src + 'A' - 'a';
else if (*Src == '\\')
*Dst = '/';
else
*Dst = *Src;
Src++;
Dst++;
}
if (Dst - Name <= 4)
continue;
Dst -= 4;
if (memcmp(Dst, ".PNG", 4))
continue;
*Dst = 0;
lcTexture* Texture = new lcTexture();
mTextures.Add(Texture);
strncpy(Texture->mName, Name, sizeof(Texture->mName));
Texture->mName[sizeof(Texture->mName) - 1] = 0;
}
return true;
2012-09-29 02:16:43 +02:00
}
2012-11-09 01:07:53 +01:00
bool lcPiecesLibrary::OpenCache()
{
struct stat CacheStat;
if (stat(mCacheFileName, &CacheStat) != 0 || mCacheFileModifiedTime != CacheStat.st_mtime)
return false;
mCacheFile = new lcZipFile;
if (!mCacheFile->OpenRead(mCacheFileName))
{
delete mCacheFile;
return false;
}
return true;
}
void lcPiecesLibrary::CloseCache()
{
delete mCacheFile;
mCacheFile = NULL;
SaveCacheFile();
}
2012-11-08 05:05:52 +01:00
bool lcPiecesLibrary::LoadCacheIndex(lcZipFile& CacheFile)
{
lcMemFile IndexFile;
if (!CacheFile.ExtractFile("index", IndexFile))
return false;
lcuint32 NumFiles;
if (!IndexFile.ReadU32(&NumFiles, 1) || NumFiles != (lcuint32)mPieces.GetSize())
return false;
for (int PieceInfoIndex = 0; PieceInfoIndex < mPieces.GetSize(); PieceInfoIndex++)
{
PieceInfo* Info = mPieces[PieceInfoIndex];
lcuint8 Length;
if (!IndexFile.ReadU8(&Length, 1) || Length >= sizeof(Info->m_strDescription))
return false;
if (!IndexFile.ReadBuffer(Info->m_strDescription, Length) || !IndexFile.ReadU32(&Info->mFlags, 1))
return false;
Info->m_strDescription[Length] = 0;
if (!IndexFile.ReadFloats(Info->m_fDimensions, 6))
return false;
}
return true;
}
bool lcPiecesLibrary::LoadCachePiece(PieceInfo* Info)
{
if ((Info->mFlags & LC_PIECE_CACHED) == 0)
return false;
2012-11-09 01:07:53 +01:00
if (mCacheFile)
{
lcMemFile PieceFile;
2012-11-08 05:05:52 +01:00
2012-11-09 01:07:53 +01:00
if (!mCacheFile->ExtractFile(Info->m_strName, PieceFile))
return false;
2012-11-08 05:05:52 +01:00
2012-11-09 01:07:53 +01:00
Info->mMesh = new lcMesh;
2012-11-08 05:05:52 +01:00
2012-11-09 01:07:53 +01:00
return Info->mMesh->FileLoad(PieceFile);
}
else
{
struct stat CacheStat;
2012-11-08 05:05:52 +01:00
2012-11-09 01:07:53 +01:00
if (stat(mCacheFileName, &CacheStat) != 0 || mCacheFileModifiedTime != CacheStat.st_mtime)
return false;
2012-11-08 05:05:52 +01:00
2012-11-09 01:07:53 +01:00
lcZipFile CacheFile;
2012-11-08 05:05:52 +01:00
2012-11-09 01:07:53 +01:00
if (!CacheFile.OpenRead(mCacheFileName))
return false;
lcMemFile PieceFile;
if (!CacheFile.ExtractFile(Info->m_strName, PieceFile))
return false;
2012-11-08 05:05:52 +01:00
2012-11-09 01:07:53 +01:00
Info->mMesh = new lcMesh;
return Info->mMesh->FileLoad(PieceFile);
}
2012-11-08 05:05:52 +01:00
}
void lcPiecesLibrary::SaveCacheFile()
{
struct stat CacheStat;
lcZipFile CacheFile;
2012-11-09 01:07:53 +01:00
if (!mSaveCache)
return;
2012-11-08 05:05:52 +01:00
if (stat(mCacheFileName, &CacheStat) != 0 || mCacheFileModifiedTime != CacheStat.st_mtime)
{
if (!CacheFile.OpenWrite(mCacheFileName, false))
return;
struct stat LibraryStat;
if (stat(mLibraryFileName, &LibraryStat) != 0)
return;
lcMemFile VersionFile;
VersionFile.WriteU32(LC_LIBRARY_CACHE_VERSION);
VersionFile.WriteU32(LC_LIBRARY_CACHE_ARCHIVE);
VersionFile.WriteU64(LibraryStat.st_size);
VersionFile.WriteU64(LibraryStat.st_mtime);
CacheFile.AddFile("version", VersionFile);
}
else
{
if (!CacheFile.OpenWrite(mCacheFileName, true))
return;
CacheFile.DeleteFile("index");
}
lcMemFile IndexFile;
int NumPieces = 0;
IndexFile.WriteU32(0);
for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++)
{
PieceInfo* Info = mPieces[PieceIdx];
if (Info->mFlags & LC_PIECE_PLACEHOLDER)
continue;
bool Cached = (Info->mFlags & LC_PIECE_CACHED) != 0;
if (Info->mMesh)
Info->mFlags |= LC_PIECE_CACHED;
int Length = strlen(Info->m_strDescription);
IndexFile.WriteU8(Length);
IndexFile.WriteBuffer(Info->m_strDescription, Length);
IndexFile.WriteU32(Info->mFlags);
IndexFile.WriteFloats(Info->m_fDimensions, 6);
NumPieces++;
if (Cached || !Info->mMesh)
continue;
lcMemFile PieceFile;
Info->mMesh->FileSave(PieceFile);
CacheFile.AddFile(Info->m_strName, PieceFile);
Info->mFlags |= LC_PIECE_CACHED;
Info->Release();
}
IndexFile.Seek(0, SEEK_SET);
IndexFile.WriteU32(mPieces.GetSize());
CacheFile.AddFile("index", IndexFile);
2012-11-09 01:07:53 +01:00
mSaveCache = false;
2012-11-08 05:05:52 +01:00
}
2012-10-16 02:43:52 +02:00
int LibraryMeshSectionCompare(const lcLibraryMeshSection* a, const lcLibraryMeshSection* b, void* Data)
{
if (a->mPrimitiveType != b->mPrimitiveType)
{
int PrimitiveOrder[LC_MESH_NUM_PRIMITIVE_TYPES] =
{
LC_MESH_TRIANGLES,
LC_MESH_TEXTURED_TRIANGLES,
LC_MESH_LINES,
LC_MESH_TEXTURED_LINES,
};
for (int PrimitiveType = 0; PrimitiveType < LC_MESH_NUM_PRIMITIVE_TYPES; PrimitiveType++)
{
int Primitive = PrimitiveOrder[PrimitiveType];
if (a->mPrimitiveType == Primitive)
return -1;
if (b->mPrimitiveType == Primitive)
return 1;
}
}
bool TranslucentA = lcIsColorTranslucent(a->mColor);
bool TranslucentB = lcIsColorTranslucent(b->mColor);
if (TranslucentA != TranslucentB)
return TranslucentA ? 1 : -1;
return a->mColor > b->mColor ? -1 : 1;
}
bool lcPiecesLibrary::LoadPiece(PieceInfo* Info)
2012-09-29 02:16:43 +02:00
{
lcLibraryMeshData MeshData;
2012-10-12 01:55:55 +02:00
ObjArray<lcLibraryTextureMap> TextureStack;
2012-09-29 02:16:43 +02:00
if (mZipFile)
{
2012-11-08 05:05:52 +01:00
if (LoadCachePiece(Info))
return true;
lcMemFile PieceFile;
2012-09-29 02:16:43 +02:00
if (!mZipFile->ExtractFile(Info->mZipFileIndex, PieceFile))
return false;
2012-10-12 01:55:55 +02:00
if (!ReadMeshData(PieceFile, lcMatrix44Identity(), 16, TextureStack, MeshData))
return false;
}
else
{
2012-10-04 23:08:05 +02:00
char Name[LC_PIECE_NAME_LEN];
strcpy(Name, Info->m_strName);
strlwr(Name);
char FileName[LC_MAXPATH];
lcDiskFile PieceFile;
2012-10-04 23:08:05 +02:00
sprintf(FileName, "%sparts/%s.dat", mLibraryPath, Name);
if (!PieceFile.Open(FileName, "rt"))
return false;
2012-10-12 01:55:55 +02:00
if (!ReadMeshData(PieceFile, lcMatrix44Identity(), 16, TextureStack, MeshData))
return false;
}
2012-09-29 02:16:43 +02:00
lcMesh* Mesh = new lcMesh();
int NumIndices = 0;
for (int SectionIdx = 0; SectionIdx < MeshData.mSections.GetSize(); SectionIdx++)
2012-10-16 02:43:52 +02:00
{
lcLibraryMeshSection* Section = MeshData.mSections[SectionIdx];
Section->mColor = lcGetColorIndex(Section->mColor);
NumIndices += Section->mIndices.GetSize();
}
MeshData.mSections.Sort(LibraryMeshSectionCompare, NULL);
2012-09-29 02:16:43 +02:00
2012-10-12 01:55:55 +02:00
Mesh->Create(MeshData.mSections.GetSize(), MeshData.mVertices.GetSize(), MeshData.mTexturedVertices.GetSize(), NumIndices);
2012-09-29 02:16:43 +02:00
2012-10-12 01:55:55 +02:00
lcVertex* DstVerts = (lcVertex*)Mesh->mVertexBuffer.mData;
2012-09-29 02:16:43 +02:00
lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX, -FLT_MAX);
for (int VertexIdx = 0; VertexIdx < MeshData.mVertices.GetSize(); VertexIdx++)
{
2012-10-12 01:55:55 +02:00
lcVertex& DstVertex = *DstVerts++;
const lcVector3& SrcPosition = MeshData.mVertices[VertexIdx].Position;
lcVector3& DstPosition = DstVertex.Position;
DstPosition = lcVector3(SrcPosition.x / 25.0f, SrcPosition.z / 25.0f, -SrcPosition.y / 25.0f);
Min.x = lcMin(Min.x, DstPosition.x);
Min.y = lcMin(Min.y, DstPosition.y);
Min.z = lcMin(Min.z, DstPosition.z);
Max.x = lcMax(Max.x, DstPosition.x);
Max.y = lcMax(Max.y, DstPosition.y);
Max.z = lcMax(Max.z, DstPosition.z);
}
lcVertexTextured* DstTexturedVerts = (lcVertexTextured*)DstVerts;
for (int VertexIdx = 0; VertexIdx < MeshData.mTexturedVertices.GetSize(); VertexIdx++)
{
lcVertexTextured& DstVertex = *DstTexturedVerts++;
lcVertexTextured& SrcVertex = MeshData.mTexturedVertices[VertexIdx];
const lcVector3& SrcPosition = SrcVertex.Position;
lcVector3& DstPosition = DstVertex.Position;
DstPosition = lcVector3(SrcPosition.x / 25.0f, SrcPosition.z / 25.0f, -SrcPosition.y / 25.0f);
DstVertex.TexCoord = SrcVertex.TexCoord;
2012-09-29 02:16:43 +02:00
2012-10-12 01:55:55 +02:00
Min.x = lcMin(Min.x, DstPosition.x);
Min.y = lcMin(Min.y, DstPosition.y);
Min.z = lcMin(Min.z, DstPosition.z);
Max.x = lcMax(Max.x, DstPosition.x);
Max.y = lcMax(Max.y, DstPosition.y);
Max.z = lcMax(Max.z, DstPosition.z);
2012-09-29 02:16:43 +02:00
}
Info->m_fDimensions[0] = Max.x;
Info->m_fDimensions[1] = Max.y;
Info->m_fDimensions[2] = Max.z;
Info->m_fDimensions[3] = Min.x;
Info->m_fDimensions[4] = Min.y;
Info->m_fDimensions[5] = Min.z;
NumIndices = 0;
for (int SectionIdx = 0; SectionIdx < MeshData.mSections.GetSize(); SectionIdx++)
{
lcMeshSection& DstSection = Mesh->mSections[SectionIdx];
lcLibraryMeshSection* SrcSection = MeshData.mSections[SectionIdx];
2012-10-16 02:43:52 +02:00
DstSection.ColorIndex = SrcSection->mColor;
2012-10-12 01:55:55 +02:00
DstSection.PrimitiveType = (SrcSection->mPrimitiveType == LC_MESH_TRIANGLES || SrcSection->mPrimitiveType == LC_MESH_TEXTURED_TRIANGLES) ? GL_TRIANGLES : GL_LINES;
2012-09-29 02:16:43 +02:00
DstSection.NumIndices = SrcSection->mIndices.GetSize();
2012-10-12 01:55:55 +02:00
DstSection.Texture = SrcSection->mTexture;
if (DstSection.Texture)
DstSection.Texture->AddRef();
2012-09-29 02:16:43 +02:00
if (Mesh->mNumVertices < 0x10000)
{
DstSection.IndexOffset = NumIndices * 2;
lcuint16* Index = (lcuint16*)Mesh->mIndexBuffer.mData + NumIndices;
for (int IndexIdx = 0; IndexIdx < DstSection.NumIndices; IndexIdx++)
*Index++ = SrcSection->mIndices[IndexIdx];
}
else
{
DstSection.IndexOffset = NumIndices * 4;
lcuint32* Index = (lcuint32*)Mesh->mIndexBuffer.mData + NumIndices;
for (int IndexIdx = 0; IndexIdx < DstSection.NumIndices; IndexIdx++)
*Index++ = SrcSection->mIndices[IndexIdx];
}
2012-10-12 01:55:55 +02:00
if (DstSection.PrimitiveType == GL_TRIANGLES)
2012-09-29 02:16:43 +02:00
{
if (DstSection.ColorIndex == gDefaultColor)
Info->mFlags |= LC_PIECE_HAS_DEFAULT;
2012-09-29 02:16:43 +02:00
else
{
if (lcIsColorTranslucent(DstSection.ColorIndex))
Info->mFlags |= LC_PIECE_HAS_TRANSLUCENT;
2012-09-29 02:16:43 +02:00
else
Info->mFlags |= LC_PIECE_HAS_SOLID;
2012-09-29 02:16:43 +02:00
}
}
else
Info->mFlags |= LC_PIECE_HAS_LINES;
2012-09-29 02:16:43 +02:00
NumIndices += DstSection.NumIndices;
}
Mesh->UpdateBuffers();
Info->mMesh = Mesh;
2012-11-08 05:05:52 +01:00
Info->AddRef();
if (mZipFile)
mSaveCache = true;
2012-09-29 02:16:43 +02:00
return true;
}
2012-10-12 01:55:55 +02:00
bool lcPiecesLibrary::LoadTexture(lcTexture* Texture)
{
char Name[LC_MAXPATH], FileName[LC_MAXPATH];
strcpy(Name, Texture->mName);
strlwr(Name);
if (mZipFile)
{
lcMemFile TextureFile;
sprintf(FileName, "parts/textures/%s.png", Name);
if (!mZipFile->ExtractFile(FileName, TextureFile))
return false;
if (!Texture->Load(TextureFile))
return false;
}
else
{
lcDiskFile TextureFile;
sprintf(FileName, "%sparts/textures/%s.png", mLibraryPath, Name);
if (!TextureFile.Open(FileName, "rb"))
return false;
if (!Texture->Load(TextureFile))
return false;
}
return true;
}
2012-09-29 02:16:43 +02:00
int lcPiecesLibrary::FindPrimitiveIndex(const char* Name)
{
for (int PrimitiveIndex = 0; PrimitiveIndex < mPrimitives.GetSize(); PrimitiveIndex++)
if (!strcmp(mPrimitives[PrimitiveIndex]->mName, Name))
return PrimitiveIndex;
return -1;
2012-09-20 02:53:12 +02:00
}
2012-09-29 02:16:43 +02:00
bool lcPiecesLibrary::LoadPrimitive(int PrimitiveIndex)
2012-09-20 02:53:12 +02:00
{
2012-09-29 02:16:43 +02:00
lcLibraryPrimitive* Primitive = mPrimitives[PrimitiveIndex];
2012-10-12 01:55:55 +02:00
ObjArray<lcLibraryTextureMap> TextureStack;
2012-09-29 02:16:43 +02:00
if (mZipFile)
{
lcMemFile PrimFile;
2012-09-29 02:16:43 +02:00
if (!mZipFile->ExtractFile(Primitive->mZipFileIndex, PrimFile))
return false;
2012-10-12 01:55:55 +02:00
if (!ReadMeshData(PrimFile, lcMatrix44Identity(), 16, TextureStack, Primitive->mMeshData))
return false;
}
else
{
2012-10-04 23:08:05 +02:00
char Name[LC_PIECE_NAME_LEN];
strcpy(Name, Primitive->mName);
strlwr(Name);
char FileName[LC_MAXPATH];
lcDiskFile PrimFile;
if (Primitive->mSubFile)
2012-10-04 23:08:05 +02:00
sprintf(FileName, "%sparts/%s.dat", mLibraryPath, Name);
else
2012-10-04 23:08:05 +02:00
sprintf(FileName, "%sp/%s.dat", mLibraryPath, Name);
if (!PrimFile.Open(FileName, "rt"))
return false;
2012-10-12 01:55:55 +02:00
if (!ReadMeshData(PrimFile, lcMatrix44Identity(), 16, TextureStack, Primitive->mMeshData))
return false;
}
2012-09-29 02:16:43 +02:00
Primitive->mLoaded = true;
2012-09-20 02:53:12 +02:00
return true;
}
2012-09-29 02:16:43 +02:00
2012-10-12 01:55:55 +02:00
bool lcPiecesLibrary::ReadMeshData(lcFile& File, const lcMatrix44& CurrentTransform, lcuint32 CurrentColorCode, ObjArray<lcLibraryTextureMap>& TextureStack, lcLibraryMeshData& MeshData)
2012-09-29 02:16:43 +02:00
{
2012-10-12 01:55:55 +02:00
char Buffer[1024];
char* Line;
2012-09-29 02:16:43 +02:00
2012-10-12 01:55:55 +02:00
while (File.ReadLine(Buffer, sizeof(Buffer)))
2012-09-29 02:16:43 +02:00
{
lcuint32 ColorCode, ColorCodeHex;
int LineType;
2012-10-12 01:55:55 +02:00
Line = Buffer;
2012-09-29 02:16:43 +02:00
if (sscanf(Line, "%d", &LineType) != 1)
continue;
2012-10-12 01:55:55 +02:00
if (LineType == 0)
{
char* Token = Line;
while (*Token && *Token <= 32)
Token++;
Token++;
while (*Token && *Token <= 32)
Token++;
char* End = Token;
while (*End && *End > 32)
End++;
*End = 0;
if (!strcmp(Token, "!TEXMAP"))
{
Token += 8;
while (*Token && *Token <= 32)
Token++;
End = Token;
while (*End && *End > 32)
End++;
*End = 0;
bool Start = false;
bool Next = false;
if (!strcmp(Token, "START"))
{
Token += 6;
Start = true;
}
else if (!strcmp(Token, "NEXT"))
{
Token += 5;
Next = true;
}
if (Start || Next)
{
while (*Token && *Token <= 32)
Token++;
End = Token;
while (*End && *End > 32)
End++;
*End = 0;
if (!strcmp(Token, "PLANAR"))
{
Token += 7;
char FileName[LC_MAXPATH];
lcVector3 Points[3];
sscanf(Token, "%f %f %f %f %f %f %f %f %f %s", &Points[0].x, &Points[0].y, &Points[0].z, &Points[1].x, &Points[1].y, &Points[1].z, &Points[2].x, &Points[2].y, &Points[2].z, FileName);
char* Ch;
for (Ch = FileName; *Ch; Ch++)
{
if (*Ch >= 'a' && *Ch <= 'z')
*Ch = *Ch + 'A' - 'a';
else if (*Ch == '\\')
*Ch = '/';
}
if (Ch - FileName > 4)
{
Ch -= 4;
if (!memcmp(Ch, ".PNG", 4))
*Ch = 0;
}
lcLibraryTextureMap& Map = TextureStack.Add();
Map.Next = false;
Map.Fallback = false;
Map.Texture = FindTexture(FileName);
for (int EdgeIdx = 0; EdgeIdx < 2; EdgeIdx++)
{
lcVector3 Normal = Points[EdgeIdx + 1] - Points[0];
float Length = lcLength(Normal);
Normal /= Length;
Map.Params[EdgeIdx].x = Normal.x / Length;
Map.Params[EdgeIdx].y = Normal.y / Length;
Map.Params[EdgeIdx].z = Normal.z / Length;
Map.Params[EdgeIdx].w = -lcDot(Normal, Points[0]) / Length;
}
}
}
else if (!strcmp(Token, "FALLBACK"))
{
if (TextureStack.GetSize())
TextureStack[TextureStack.GetSize() - 1].Fallback = true;
}
else if (!strcmp(Token, "END"))
{
if (TextureStack.GetSize())
TextureStack.RemoveIndex(TextureStack.GetSize() - 1);
}
continue;
}
else if (!strcmp(Token, "!:"))
{
Token += 3;
Line = Token;
if (!TextureStack.GetSize())
continue;
}
else
continue;
}
2012-09-29 02:16:43 +02:00
if (sscanf(Line, "%d %d", &LineType, &ColorCode) != 2)
continue;
2012-10-12 01:55:55 +02:00
if (LineType < 1 || LineType > 4)
continue;
2012-09-29 02:16:43 +02:00
if (ColorCode == 0)
{
sscanf(Line, "%d %i", &LineType, &ColorCodeHex);
if (ColorCode != ColorCodeHex)
ColorCode = ColorCodeHex | LC_COLOR_DIRECT;
}
if (ColorCode == 16)
ColorCode = CurrentColorCode;
2012-10-12 01:55:55 +02:00
lcLibraryTextureMap* TextureMap = NULL;
if (TextureStack.GetSize())
{
TextureMap = &TextureStack[TextureStack.GetSize() - 1];
if (TextureMap->Fallback)
continue;
}
2012-09-29 02:16:43 +02:00
int Dummy;
lcVector3 Points[4];
switch (LineType)
{
case 1:
{
char FileName[LC_MAXPATH];
float fm[12];
sscanf(Line, "%d %i %f %f %f %f %f %f %f %f %f %f %f %f %s", &LineType, &Dummy, &fm[0], &fm[1], &fm[2], &fm[3], &fm[4], &fm[5], &fm[6], &fm[7], &fm[8], &fm[9], &fm[10], &fm[11], FileName);
char* Ch;
for (Ch = FileName; *Ch; Ch++)
{
if (*Ch >= 'a' && *Ch <= 'z')
*Ch = *Ch + 'A' - 'a';
else if (*Ch == '\\')
*Ch = '/';
}
if (Ch - FileName > 4)
{
Ch -= 4;
if (!memcmp(Ch, ".DAT", 4))
*Ch = 0;
}
int PrimitiveIndex = FindPrimitiveIndex(FileName);
lcMatrix44 IncludeTransform(lcVector4(fm[3], fm[6], fm[9], 0.0f), lcVector4(fm[4], fm[7], fm[10], 0.0f), lcVector4(fm[5], fm[8], fm[11], 0.0f), lcVector4(fm[0], fm[1], fm[2], 1.0f));
IncludeTransform = lcMul(IncludeTransform, CurrentTransform);
if (PrimitiveIndex != -1)
{
lcLibraryPrimitive* Primitive = mPrimitives[PrimitiveIndex];
if (!Primitive->mLoaded && !LoadPrimitive(PrimitiveIndex))
continue;
if (Primitive->mStud)
2012-10-12 01:55:55 +02:00
MeshData.AddMeshDataNoDuplicateCheck(Primitive->mMeshData, IncludeTransform, ColorCode, TextureMap);
2012-09-29 02:16:43 +02:00
else if (!Primitive->mSubFile)
2012-10-12 01:55:55 +02:00
MeshData.AddMeshData(Primitive->mMeshData, IncludeTransform, ColorCode, TextureMap);
2012-09-29 02:16:43 +02:00
else
{
if (mZipFile)
{
lcMemFile IncludeFile;
if (!mZipFile->ExtractFile(Primitive->mZipFileIndex, IncludeFile))
continue;
2012-10-12 01:55:55 +02:00
if (!ReadMeshData(IncludeFile, IncludeTransform, ColorCode, TextureStack, MeshData))
continue;
}
else
{
2012-10-04 23:08:05 +02:00
char Name[LC_PIECE_NAME_LEN];
strcpy(Name, Primitive->mName);
strlwr(Name);
char FileName[LC_MAXPATH];
lcDiskFile IncludeFile;
if (Primitive->mSubFile)
2012-10-04 23:08:05 +02:00
sprintf(FileName, "%sparts/%s.dat", mLibraryPath, Name);
else
2012-10-04 23:08:05 +02:00
sprintf(FileName, "%sp/%s.dat", mLibraryPath, Name);
if (!IncludeFile.Open(FileName, "rt"))
continue;
2012-10-12 01:55:55 +02:00
if (!ReadMeshData(IncludeFile, IncludeTransform, ColorCode, TextureStack, MeshData))
continue;
}
2012-09-29 02:16:43 +02:00
}
}
else
{
for (int PieceInfoIndex = 0; PieceInfoIndex < mPieces.GetSize(); PieceInfoIndex++)
{
PieceInfo* Info = mPieces[PieceInfoIndex];
if (strcmp(Info->m_strName, FileName))
continue;
if (mZipFile)
{
lcMemFile IncludeFile;
if (!mZipFile->ExtractFile(Info->mZipFileIndex, IncludeFile))
break;
2012-10-12 01:55:55 +02:00
if (!ReadMeshData(IncludeFile, IncludeTransform, ColorCode, TextureStack, MeshData))
break;
}
else
{
2012-10-04 23:08:05 +02:00
char Name[LC_PIECE_NAME_LEN];
strcpy(Name, Info->m_strName);
strlwr(Name);
char FileName[LC_MAXPATH];
lcDiskFile IncludeFile;
2012-09-29 02:16:43 +02:00
2012-10-04 23:08:05 +02:00
sprintf(FileName, "%sparts/%s.dat", mLibraryPath, Name);
2012-09-29 02:16:43 +02:00
if (!IncludeFile.Open(FileName, "rt"))
break;
2012-10-12 01:55:55 +02:00
if (!ReadMeshData(IncludeFile, IncludeTransform, ColorCode, TextureStack, MeshData))
break;
}
2012-09-29 02:16:43 +02:00
break;
}
}
} break;
case 2:
{
sscanf(Line, "%d %i %f %f %f %f %f %f", &LineType, &Dummy, &Points[0].x, &Points[0].y, &Points[0].z, &Points[1].x, &Points[1].y, &Points[1].z);
Points[0] = lcMul31(Points[0], CurrentTransform);
Points[1] = lcMul31(Points[1], CurrentTransform);
2012-10-12 01:55:55 +02:00
if (TextureMap)
{
MeshData.AddTexturedLine(LineType, ColorCode, *TextureMap, Points);
if (TextureMap->Next)
TextureStack.RemoveIndex(TextureStack.GetSize() - 1);
}
else
MeshData.AddLine(LineType, ColorCode, Points);
2012-09-29 02:16:43 +02:00
} break;
case 3:
{
sscanf(Line, "%d %i %f %f %f %f %f %f %f %f %f", &LineType, &Dummy, &Points[0].x, &Points[0].y, &Points[0].z,
&Points[1].x, &Points[1].y, &Points[1].z, &Points[2].x, &Points[2].y, &Points[2].z);
Points[0] = lcMul31(Points[0], CurrentTransform);
Points[1] = lcMul31(Points[1], CurrentTransform);
Points[2] = lcMul31(Points[2], CurrentTransform);
2012-10-12 01:55:55 +02:00
if (TextureMap)
{
MeshData.AddTexturedLine(LineType, ColorCode, *TextureMap, Points);
if (TextureMap->Next)
TextureStack.RemoveIndex(TextureStack.GetSize() - 1);
}
else
MeshData.AddLine(LineType, ColorCode, Points);
2012-09-29 02:16:43 +02:00
} break;
case 4:
{
sscanf(Line, "%d %i %f %f %f %f %f %f %f %f %f %f %f %f", &LineType, &Dummy, &Points[0].x, &Points[0].y, &Points[0].z,
&Points[1].x, &Points[1].y, &Points[1].z, &Points[2].x, &Points[2].y, &Points[2].z, &Points[3].x, &Points[3].y, &Points[3].z);
Points[0] = lcMul31(Points[0], CurrentTransform);
Points[1] = lcMul31(Points[1], CurrentTransform);
Points[2] = lcMul31(Points[2], CurrentTransform);
Points[3] = lcMul31(Points[3], CurrentTransform);
2012-10-12 01:55:55 +02:00
if (TextureMap)
{
MeshData.AddTexturedLine(LineType, ColorCode, *TextureMap, Points);
if (TextureMap->Next)
TextureStack.RemoveIndex(TextureStack.GetSize() - 1);
}
else
MeshData.AddLine(LineType, ColorCode, Points);
2012-09-29 02:16:43 +02:00
} break;
}
}
return true;
}
void lcLibraryMeshData::AddLine(int LineType, lcuint32 ColorCode, const lcVector3* Vertices)
{
2012-10-17 00:24:43 +02:00
lcLibraryMeshSection* Section = NULL;
2012-09-29 02:16:43 +02:00
int SectionIdx;
2012-10-12 01:55:55 +02:00
LC_MESH_PRIMITIVE_TYPE PrimitiveType = (LineType == 2) ? LC_MESH_LINES : LC_MESH_TRIANGLES;
2012-09-29 02:16:43 +02:00
for (SectionIdx = 0; SectionIdx < mSections.GetSize(); SectionIdx++)
{
Section = mSections[SectionIdx];
2012-10-16 02:43:52 +02:00
if (Section->mColor == ColorCode && Section->mPrimitiveType == PrimitiveType)
2012-09-29 02:16:43 +02:00
break;
}
if (SectionIdx == mSections.GetSize())
{
2012-10-12 01:55:55 +02:00
Section = new lcLibraryMeshSection(PrimitiveType, ColorCode, NULL);
2012-09-29 02:16:43 +02:00
mSections.Add(Section);
}
int Indices[4] = { -1, -1, -1, -1 };
for (int IndexIdx = 0; IndexIdx < LineType; IndexIdx++)
{
2012-10-12 01:55:55 +02:00
const lcVector3& Position = Vertices[IndexIdx];
2012-09-29 02:16:43 +02:00
for (int VertexIdx = mVertices.GetSize() - 1; VertexIdx >= 0; VertexIdx--)
{
2012-10-12 01:55:55 +02:00
lcVertex& DstVertex = mVertices[VertexIdx];
if (Position == DstVertex.Position)
2012-09-29 02:16:43 +02:00
{
Indices[IndexIdx] = VertexIdx;
break;
}
}
if (Indices[IndexIdx] == -1)
{
Indices[IndexIdx] = mVertices.GetSize();
2012-10-12 01:55:55 +02:00
lcVertex& DstVertex = mVertices.Add();
DstVertex.Position = Position;
2012-09-29 02:16:43 +02:00
}
}
switch (LineType)
{
case 4:
if (Indices[0] != Indices[2] && Indices[0] != Indices[3] && Indices[2] != Indices[3])
{
Section->mIndices.Add(Indices[2]);
Section->mIndices.Add(Indices[3]);
Section->mIndices.Add(Indices[0]);
}
2012-09-29 02:16:43 +02:00
case 3:
if (Indices[0] != Indices[1] && Indices[0] != Indices[2] && Indices[1] != Indices[2])
{
Section->mIndices.Add(Indices[0]);
Section->mIndices.Add(Indices[1]);
Section->mIndices.Add(Indices[2]);
}
2012-09-29 02:16:43 +02:00
break;
case 2:
if (Indices[0] != Indices[1])
{
Section->mIndices.Add(Indices[0]);
Section->mIndices.Add(Indices[1]);
}
2012-09-29 02:16:43 +02:00
break;
}
}
2012-10-12 01:55:55 +02:00
void lcLibraryMeshData::AddTexturedLine(int LineType, lcuint32 ColorCode, const lcLibraryTextureMap& Map, const lcVector3* Vertices)
2012-09-29 02:16:43 +02:00
{
2012-10-17 00:24:43 +02:00
lcLibraryMeshSection* Section = NULL;
2012-10-12 01:55:55 +02:00
int SectionIdx;
LC_MESH_PRIMITIVE_TYPE PrimitiveType = (LineType == 2) ? LC_MESH_TEXTURED_LINES : LC_MESH_TEXTURED_TRIANGLES;
for (SectionIdx = 0; SectionIdx < mSections.GetSize(); SectionIdx++)
{
Section = mSections[SectionIdx];
2012-10-16 02:43:52 +02:00
if (Section->mColor == ColorCode && Section->mPrimitiveType == PrimitiveType)
2012-10-12 01:55:55 +02:00
break;
}
if (SectionIdx == mSections.GetSize())
{
Section = new lcLibraryMeshSection(PrimitiveType, ColorCode, Map.Texture);
2012-09-29 02:16:43 +02:00
2012-10-12 01:55:55 +02:00
mSections.Add(Section);
}
2012-09-29 02:16:43 +02:00
2012-10-12 01:55:55 +02:00
int Indices[4] = { -1, -1, -1, -1 };
for (int IndexIdx = 0; IndexIdx < LineType; IndexIdx++)
2012-09-29 02:16:43 +02:00
{
2012-10-12 01:55:55 +02:00
const lcVector3& Position = Vertices[IndexIdx];
lcVector2 TexCoord(lcDot3(lcVector3(Position.x, Position.y, Position.z), Map.Params[0]) + Map.Params[0].w,
lcDot3(lcVector3(Position.x, Position.y, Position.z), Map.Params[1]) + Map.Params[1].w);
2012-09-29 02:16:43 +02:00
2012-10-12 01:55:55 +02:00
for (int VertexIdx = mTexturedVertices.GetSize() - 1; VertexIdx >= 0; VertexIdx--)
2012-09-29 02:16:43 +02:00
{
2012-10-12 01:55:55 +02:00
lcVertexTextured& DstVertex = mTexturedVertices[VertexIdx];
if (Position == DstVertex.Position && TexCoord == DstVertex.TexCoord)
2012-09-29 02:16:43 +02:00
{
2012-10-12 01:55:55 +02:00
Indices[IndexIdx] = VertexIdx;
2012-09-29 02:16:43 +02:00
break;
}
}
2012-10-12 01:55:55 +02:00
if (Indices[IndexIdx] == -1)
{
Indices[IndexIdx] = mTexturedVertices.GetSize();
lcVertexTextured& DstVertex = mTexturedVertices.Add();
DstVertex.Position = Position;
DstVertex.TexCoord = TexCoord;
}
}
switch (LineType)
{
case 4:
if (Indices[0] != Indices[2] && Indices[0] != Indices[3] && Indices[2] != Indices[3])
{
Section->mIndices.Add(Indices[2]);
Section->mIndices.Add(Indices[3]);
Section->mIndices.Add(Indices[0]);
}
case 3:
if (Indices[0] != Indices[1] && Indices[0] != Indices[2] && Indices[1] != Indices[2])
{
Section->mIndices.Add(Indices[0]);
Section->mIndices.Add(Indices[1]);
Section->mIndices.Add(Indices[2]);
}
break;
case 2:
if (Indices[0] != Indices[1])
{
Section->mIndices.Add(Indices[0]);
Section->mIndices.Add(Indices[1]);
}
break;
}
}
void lcLibraryMeshData::AddMeshData(const lcLibraryMeshData& Data, const lcMatrix44& Transform, lcuint32 CurrentColorCode, lcLibraryTextureMap* TextureMap)
{
int VertexCount = Data.mVertices.GetSize();
ObjArray<lcuint32> IndexRemap(VertexCount);
if (!TextureMap)
{
mVertices.Expand(VertexCount);
for (int SrcVertexIdx = 0; SrcVertexIdx < VertexCount; SrcVertexIdx++)
{
lcVector3 Position = lcMul31(Data.mVertices[SrcVertexIdx].Position, Transform);
int Index = -1;
for (int DstVertexIdx = mVertices.GetSize() - 1; DstVertexIdx >= 0; DstVertexIdx--)
{
lcVertex& DstVertex = mVertices[DstVertexIdx];
// if (Vertex == mVertices[DstVertexIdx])
if (fabsf(Position.x - DstVertex.Position.x) < 0.1f && fabsf(Position.y - DstVertex.Position.y) < 0.1f && fabsf(Position.z - DstVertex.Position.z) < 0.1f)
{
Index = DstVertexIdx;
break;
}
}
if (Index == -1)
{
Index = mVertices.GetSize();
lcVertex& DstVertex = mVertices.Add();
DstVertex.Position = Position;
}
IndexRemap.Add(Index);
}
}
else
{
mTexturedVertices.Expand(VertexCount);
for (int SrcVertexIdx = 0; SrcVertexIdx < VertexCount; SrcVertexIdx++)
2012-09-29 02:16:43 +02:00
{
2012-10-12 01:55:55 +02:00
lcVertex& SrcVertex = Data.mVertices[SrcVertexIdx];
lcVector3 Position = lcMul31(SrcVertex.Position, Transform);
lcVector2 TexCoord(lcDot3(lcVector3(Position.x, Position.y, Position.z), TextureMap->Params[0]) + TextureMap->Params[0].w,
lcDot3(lcVector3(Position.x, Position.y, Position.z), TextureMap->Params[1]) + TextureMap->Params[1].w);
int Index = -1;
for (int DstVertexIdx = mTexturedVertices.GetSize() - 1; DstVertexIdx >= 0; DstVertexIdx--)
{
lcVertexTextured& DstVertex = mTexturedVertices[DstVertexIdx];
// if (Vertex == mTexturedVertices[DstVertexIdx])
if (fabsf(Position.x - DstVertex.Position.x) < 0.1f && fabsf(Position.y - DstVertex.Position.y) < 0.1f && fabsf(Position.z - DstVertex.Position.z) < 0.1f &&
fabsf(TexCoord.x - DstVertex.TexCoord.x) < 0.01f && fabsf(TexCoord.y - DstVertex.TexCoord.y) < 0.01f)
{
Index = DstVertexIdx;
break;
}
}
if (Index == -1)
{
Index = mTexturedVertices.GetSize();
lcVertexTextured& DstVertex = mTexturedVertices.Add();
DstVertex.Position = Position;
DstVertex.TexCoord = TexCoord;
}
IndexRemap.Add(Index);
2012-09-29 02:16:43 +02:00
}
2012-10-12 01:55:55 +02:00
}
int TexturedVertexCount = Data.mTexturedVertices.GetSize();
ObjArray<lcuint32> TexturedIndexRemap(TexturedVertexCount);
if (TexturedVertexCount)
{
mTexturedVertices.Expand(TexturedVertexCount);
2012-09-29 02:16:43 +02:00
2012-10-12 01:55:55 +02:00
for (int SrcVertexIdx = 0; SrcVertexIdx < TexturedVertexCount; SrcVertexIdx++)
{
lcVertexTextured& SrcVertex = Data.mTexturedVertices[SrcVertexIdx];
lcVector3 Position = lcMul31(SrcVertex.Position, Transform);
int Index = -1;
for (int DstVertexIdx = mTexturedVertices.GetSize() - 1; DstVertexIdx >= 0; DstVertexIdx--)
{
lcVertexTextured& DstVertex = mTexturedVertices[DstVertexIdx];
// if (Vertex == mTexturedVertices[DstVertexIdx])
if (fabsf(Position.x - DstVertex.Position.x) < 0.1f && fabsf(Position.y - DstVertex.Position.y) < 0.1f && fabsf(Position.z - DstVertex.Position.z) < 0.1f &&
fabsf(SrcVertex.TexCoord.x - DstVertex.TexCoord.x) < 0.01f && fabsf(SrcVertex.TexCoord.y - DstVertex.TexCoord.y) < 0.01f)
{
Index = DstVertexIdx;
break;
}
}
if (Index == -1)
{
Index = mTexturedVertices.GetSize();
lcVertexTextured& DstVertex = mTexturedVertices.Add();
DstVertex.Position = Position;
DstVertex.TexCoord = SrcVertex.TexCoord;
}
TexturedIndexRemap.Add(Index);
}
2012-09-29 02:16:43 +02:00
}
for (int SrcSectionIdx = 0; SrcSectionIdx < Data.mSections.GetSize(); SrcSectionIdx++)
{
lcLibraryMeshSection* SrcSection = Data.mSections[SrcSectionIdx];
lcLibraryMeshSection* DstSection = NULL;
2012-10-16 02:43:52 +02:00
lcuint32 ColorCode = SrcSection->mColor == 16 ? CurrentColorCode : SrcSection->mColor;
2012-10-12 01:55:55 +02:00
lcTexture* Texture;
if (SrcSection->mTexture)
Texture = SrcSection->mTexture;
else if (TextureMap)
Texture = TextureMap->Texture;
else
Texture = NULL;
2012-09-29 02:16:43 +02:00
for (int DstSectionIdx = 0; DstSectionIdx < mSections.GetSize(); DstSectionIdx++)
{
lcLibraryMeshSection* Section = mSections[DstSectionIdx];
2012-10-16 02:43:52 +02:00
if (Section->mColor == ColorCode && Section->mPrimitiveType == SrcSection->mPrimitiveType && Section->mTexture == Texture)
2012-09-29 02:16:43 +02:00
{
DstSection = Section;
break;
}
}
if (!DstSection)
{
2012-10-12 01:55:55 +02:00
DstSection = new lcLibraryMeshSection(SrcSection->mPrimitiveType, ColorCode, Texture);
2012-09-29 02:16:43 +02:00
mSections.Add(DstSection);
}
DstSection->mIndices.Expand(SrcSection->mIndices.GetSize());
2012-10-12 01:55:55 +02:00
if (!SrcSection->mTexture)
{
for (int IndexIdx = 0; IndexIdx < SrcSection->mIndices.GetSize(); IndexIdx++)
DstSection->mIndices.Add(IndexRemap[SrcSection->mIndices[IndexIdx]]);
}
else
{
for (int IndexIdx = 0; IndexIdx < SrcSection->mIndices.GetSize(); IndexIdx++)
DstSection->mIndices.Add(TexturedIndexRemap[SrcSection->mIndices[IndexIdx]]);
}
2012-09-29 02:16:43 +02:00
}
}
2012-10-12 01:55:55 +02:00
void lcLibraryMeshData::AddMeshDataNoDuplicateCheck(const lcLibraryMeshData& Data, const lcMatrix44& Transform, lcuint32 CurrentColorCode, lcLibraryTextureMap* TextureMap)
2012-09-29 02:16:43 +02:00
{
2012-10-12 01:55:55 +02:00
lcuint32 BaseIndex;
2012-09-29 02:16:43 +02:00
2012-10-12 01:55:55 +02:00
if (!TextureMap)
{
BaseIndex = mVertices.GetSize();
2012-09-29 02:16:43 +02:00
2012-10-12 01:55:55 +02:00
mVertices.Expand(Data.mVertices.GetSize());
for (int SrcVertexIdx = 0; SrcVertexIdx < Data.mVertices.GetSize(); SrcVertexIdx++)
{
lcVertex& Vertex = mVertices.Add();
Vertex.Position = lcMul31(Data.mVertices[SrcVertexIdx].Position, Transform);
}
}
else
{
BaseIndex = mTexturedVertices.GetSize();
mTexturedVertices.Expand(Data.mVertices.GetSize());
for (int SrcVertexIdx = 0; SrcVertexIdx < Data.mVertices.GetSize(); SrcVertexIdx++)
{
lcVertex& SrcVertex = Data.mVertices[SrcVertexIdx];
lcVertexTextured& DstVertex = mTexturedVertices.Add();
lcVector3 Position = lcMul31(SrcVertex.Position, Transform);
lcVector2 TexCoord(lcDot3(lcVector3(Position.x, Position.y, Position.z), TextureMap->Params[0]) + TextureMap->Params[0].w,
lcDot3(lcVector3(Position.x, Position.y, Position.z), TextureMap->Params[1]) + TextureMap->Params[1].w);
DstVertex.Position = Position;
DstVertex.TexCoord = TexCoord;
}
}
int TexturedVertexCount = Data.mTexturedVertices.GetSize();
lcuint32 BaseTexturedIndex = mTexturedVertices.GetSize();
if (TexturedVertexCount)
{
mTexturedVertices.Expand(TexturedVertexCount);
for (int SrcVertexIdx = 0; SrcVertexIdx < TexturedVertexCount; SrcVertexIdx++)
{
lcVertexTextured& SrcVertex = Data.mTexturedVertices[SrcVertexIdx];
lcVertexTextured& DstVertex = mTexturedVertices.Add();
DstVertex.Position = lcMul31(SrcVertex.Position, Transform);
DstVertex.TexCoord = SrcVertex.TexCoord;
}
}
2012-09-29 02:16:43 +02:00
for (int SrcSectionIdx = 0; SrcSectionIdx < Data.mSections.GetSize(); SrcSectionIdx++)
{
lcLibraryMeshSection* SrcSection = Data.mSections[SrcSectionIdx];
lcLibraryMeshSection* DstSection = NULL;
2012-10-16 02:43:52 +02:00
lcuint32 ColorCode = SrcSection->mColor == 16 ? CurrentColorCode : SrcSection->mColor;
2012-10-12 01:55:55 +02:00
lcTexture* Texture;
if (SrcSection->mTexture)
Texture = SrcSection->mTexture;
else if (TextureMap)
Texture = TextureMap->Texture;
else
Texture = NULL;
2012-09-29 02:16:43 +02:00
for (int DstSectionIdx = 0; DstSectionIdx < mSections.GetSize(); DstSectionIdx++)
{
lcLibraryMeshSection* Section = mSections[DstSectionIdx];
2012-10-16 02:43:52 +02:00
if (Section->mColor == ColorCode && Section->mPrimitiveType == SrcSection->mPrimitiveType && Section->mTexture == Texture)
2012-09-29 02:16:43 +02:00
{
DstSection = Section;
break;
}
}
if (!DstSection)
{
2012-10-12 01:55:55 +02:00
DstSection = new lcLibraryMeshSection(SrcSection->mPrimitiveType, ColorCode, Texture);
2012-09-29 02:16:43 +02:00
mSections.Add(DstSection);
}
DstSection->mIndices.Expand(SrcSection->mIndices.GetSize());
2012-10-12 01:55:55 +02:00
if (!SrcSection->mTexture)
{
for (int IndexIdx = 0; IndexIdx < SrcSection->mIndices.GetSize(); IndexIdx++)
DstSection->mIndices.Add(BaseIndex + SrcSection->mIndices[IndexIdx]);
}
else
{
for (int IndexIdx = 0; IndexIdx < SrcSection->mIndices.GetSize(); IndexIdx++)
DstSection->mIndices.Add(BaseTexturedIndex + SrcSection->mIndices[IndexIdx]);
}
2012-09-29 02:16:43 +02:00
}
}
2012-10-02 03:23:44 +02:00
bool lcPiecesLibrary::PieceInCategory(PieceInfo* Info, const String& CategoryKeywords) const
{
2012-10-19 22:58:11 +02:00
String PieceName;
if (Info->m_strDescription[0] == '~' || Info->m_strDescription[0] == '_')
PieceName = Info->m_strDescription + 1;
else
PieceName = Info->m_strDescription;
2012-10-02 03:23:44 +02:00
PieceName.MakeLower();
String Keywords = CategoryKeywords;
Keywords.MakeLower();
return PieceName.Match(Keywords);
}
int lcPiecesLibrary::GetFirstPieceCategory(PieceInfo* Info) const
{
for (int i = 0; i < mCategories.GetSize(); i++)
if (PieceInCategory(Info, mCategories[i].Keywords))
return i;
return -1;
}
void lcPiecesLibrary::GetCategoryEntries(int CategoryIndex, bool GroupPieces, PtrArray<PieceInfo>& SinglePieces, PtrArray<PieceInfo>& GroupedPieces)
{
SinglePieces.RemoveAll();
GroupedPieces.RemoveAll();
// Don't group entries in the search results category.
if (mCategories[CategoryIndex].Name == "Search Results")
GroupPieces = false;
for (int i = 0; i < mPieces.GetSize(); i++)
{
PieceInfo* Info = mPieces[i];
if (!PieceInCategory(Info, mCategories[CategoryIndex].Keywords))
continue;
if (!GroupPieces)
{
SinglePieces.Add(Info);
continue;
}
// Check if it's a patterned piece.
if (Info->IsPatterned())
{
PieceInfo* Parent;
// Find the parent of this patterned piece.
char ParentName[LC_PIECE_NAME_LEN];
strcpy(ParentName, Info->m_strName);
*strchr(ParentName, 'P') = '\0';
Parent = FindPiece(ParentName, false);
if (Parent)
{
// Check if the parent was added as a single piece.
int Index = SinglePieces.FindIndex(Parent);
if (Index != -1)
SinglePieces.RemoveIndex(Index);
Index = GroupedPieces.FindIndex(Parent);
if (Index == -1)
GroupedPieces.Add(Parent);
}
else
{
// Patterned pieces should have a parent but in case they don't just add them anyway.
SinglePieces.Add(Info);
}
}
else
{
// Check if this piece has already been added to this category by one of its children.
int Index = GroupedPieces.FindIndex(Info);
if (Index == -1)
SinglePieces.Add(Info);
}
}
}
void lcPiecesLibrary::GetPatternedPieces(PieceInfo* Parent, PtrArray<PieceInfo>& Pieces) const
{
char Name[LC_PIECE_NAME_LEN];
strcpy(Name, Parent->m_strName);
strcat(Name, "P");
Pieces.RemoveAll();
for (int i = 0; i < mPieces.GetSize(); i++)
{
PieceInfo* Info = mPieces[i];
if (strncmp(Name, Info->m_strName, strlen(Name)) == 0)
Pieces.Add(Info);
}
// Sometimes pieces with A and B versions don't follow the same convention (for example, 3040Pxx instead of 3040BPxx).
if (Pieces.GetSize() == 0)
{
strcpy(Name, Parent->m_strName);
int Len = strlen(Name);
if (Name[Len-1] < '0' || Name[Len-1] > '9')
Name[Len-1] = 'P';
for (int i = 0; i < mPieces.GetSize(); i++)
{
PieceInfo* Info = mPieces[i];
if (strncmp(Name, Info->m_strName, strlen(Name)) == 0)
Pieces.Add(Info);
}
}
}
void lcPiecesLibrary::ResetCategories()
{
struct CategoryEntry
{
const char* Name;
const char* Keywords;
};
// Animal, Antenna, Arch, Arm, Bar, Baseplate, Belville, Boat, Bracket, Brick,
// Car, Cone, Container, Conveyor, Crane, Cylinder, Door, Electric, Exhaust,
// Fence, Flag, Forklift, Freestyle, Garage, Gate, Glass, Grab, Hinge, Homemaker,
// Hose, Jack, Ladder, Lever, Magnet, Minifig, Minifig Accessory, Panel, Plane,
// Plant, Plate, Platform, Propellor, Rack, Roadsign, Rock, Scala, Slope, Staircase,
// Support, Tail, Tap, Technic, Tile, Tipper, Tractor, Trailer, Train, Turntable,
// Tyre, Wedge, Wheel, Winch, Window, Windscreen, Wing
CategoryEntry DefaultCategories[] =
{
2012-10-19 22:58:11 +02:00
{ "Animal", "^%Animal | ^%Bone" },
2012-10-02 03:23:44 +02:00
{ "Antenna", "^%Antenna" },
{ "Arch", "^%Arch" },
{ "Bar", "^%Bar" },
{ "Baseplate", "^%Baseplate | ^%Platform" },
{ "Boat", "^%Boat" },
{ "Brick", "^%Brick" },
{ "Container", "^%Container | ^%Box | ^Chest | ^%Storage | ^Mailbox" },
{ "Door and Window", "^%Door | ^%Window | ^%Glass | ^%Freestyle | ^%Gate | ^%Garage | ^%Roller" },
2012-10-19 22:58:11 +02:00
{ "Electric", "^%Electric" },
2012-10-02 03:23:44 +02:00
{ "Hinge and Bracket", "^%Hinge | ^%Bracket | ^%Turntable" },
2012-10-19 22:58:11 +02:00
{ "Hose", "^%Hose | ^%String" },
2012-10-02 03:23:44 +02:00
{ "Minifig", "^%Minifig" },
2012-10-19 22:58:11 +02:00
{ "Miscellaneous", "^%Arm | ^%Barrel | ^%Brush | ^%Claw | ^%Cockpit | ^%Conveyor | ^%Crane | ^%Cupboard | ^%Fence | ^%Jack | ^%Ladder | ^%Motor | ^%Rock | ^%Rope | ^%Sheet | ^%Sports | ^%Staircase | ^%Stretcher | ^%Tap | ^%Tipper | ^%Trailer | ^%Umbrella | ^%Winch" },
{ "Other", "^%Ball | ^%Belville | ^%Die | ^%Duplo | ^%Fabuland | ^%Figure | ^%Homemaker | ^%Maxifig | ^%Microfig | ^%Mursten | ^%Scala | ^%Znap" },
2012-10-02 03:23:44 +02:00
{ "Panel", "^%Panel | ^%Castle Wall | ^%Castle Turret" },
{ "Plant", "^%Plant" },
{ "Plate", "^%Plate" },
2012-10-19 22:58:11 +02:00
{ "Round", "^%Cylinder | ^%Cone | ^%Dish | ^%Dome | ^%Hemisphere | ^%Round" },
2012-10-02 03:23:44 +02:00
{ "Sign and Flag", "^%Flag | ^%Roadsign | ^%Streetlight | ^%Flagpost | ^%Lamppost | ^%Signpost" },
2012-10-19 22:58:11 +02:00
{ "Slope", "^%Slope | ^%Roof" },
2012-10-02 03:23:44 +02:00
{ "Space", "^%Space" },
{ "Sticker", "^%Sticker" },
{ "Support", "^%Support" },
{ "Technic", "^%Technic | ^%Rack" },
{ "Tile", "^%Tile" },
{ "Train", "^%Train | ^%Monorail | ^%Magnet" },
2012-10-19 22:58:11 +02:00
{ "Tyre and Wheel", "^%Tyre | %^Wheel | %^Wheels | ^%Castle Wagon" },
{ "Vehicle", "^%Bike | ^%Canvas | ^%Car | ^%Excavator | ^%Exhaust | ^%Forklift | ^%Grab Jaw | ^%Landing | ^%Motorcycle | ^%Plane | ^%Propellor | ^%Tail | ^%Tractor | ^%Vehicle | ^%Wheelbarrow" },
2012-10-02 03:23:44 +02:00
{ "Windscreen", "^%Windscreen" },
{ "Wedge", "^%Wedge" },
{ "Wing", "^%Wing" },
};
const int NumCategories = sizeof(DefaultCategories)/sizeof(DefaultCategories[0]);
mCategories.RemoveAll();
for (int i = 0; i < NumCategories; i++)
{
lcLibraryCategory& Category = mCategories.Add();
Category.Name = DefaultCategories[i].Name;
Category.Keywords = DefaultCategories[i].Keywords;
}
strcpy(mCategoriesFile, "");
Sys_ProfileSaveString("Settings", "Categories", mCategoriesFile);
mCategoriesModified = false;
}
bool lcPiecesLibrary::LoadCategories(const char* FileName)
{
char Path[LC_MAXPATH];
if (FileName)
{
strcpy(Path, FileName);
}
else
{
LC_FILEOPENDLG_OPTS opts;
opts.type = LC_FILEOPENDLG_LCF;
strcpy(opts.path, mCategoriesFile);
if (!SystemDoDialog(LC_DLG_FILE_OPEN, &opts))
return false;
strcpy(Path, (char*)opts.filenames);
free(opts.filenames);
}
// Load the file.
lcDiskFile File;
if (!File.Open(Path, "rb"))
return false;
lcuint32 i;
File.ReadU32(&i, 1);
if (i != LC_FILE_ID)
return false;
File.ReadU32(&i, 1);
if (i != LC_CATEGORY_FILE_ID)
return false;
File.ReadU32(&i, 1);
if (i != LC_CATEGORY_FILE_VERSION)
return false;
mCategories.RemoveAll();
File.ReadU32(&i, 1);
while (i--)
{
lcLibraryCategory& Category = mCategories.Add();
File.ReadString(Category.Name);
File.ReadString(Category.Keywords);
}
strcpy(mCategoriesFile, Path);
Sys_ProfileSaveString("Settings", "Categories", mCategoriesFile);
mCategoriesModified = false;
return true;
}
bool lcPiecesLibrary::SaveCategories()
{
if (mCategoriesModified)
{
switch (SystemDoMessageBox("Save changes to categories?", LC_MB_YESNOCANCEL | LC_MB_ICONQUESTION))
{
case LC_CANCEL:
return false;
case LC_YES:
if (!DoSaveCategories(false))
return false;
break;
case LC_NO:
return true;
break;
}
}
return true;
}
bool lcPiecesLibrary::DoSaveCategories(bool AskName)
{
// Get the file name.
if (AskName || !mCategoriesFile[0])
2012-10-02 03:23:44 +02:00
{
LC_FILESAVEDLG_OPTS opts;
opts.type = LC_FILESAVEDLG_LCF;
strcpy(opts.path, mCategoriesFile);
if (!SystemDoDialog(LC_DLG_FILE_SAVE, &opts))
return false;
strcpy(mCategoriesFile, opts.path);
}
// Save the file.
lcDiskFile File;
if (!File.Open(mCategoriesFile, "wb"))
return false;
File.WriteU32(LC_FILE_ID);
File.WriteU32(LC_CATEGORY_FILE_ID);
File.WriteU32(LC_CATEGORY_FILE_VERSION);
int NumCategories = mCategories.GetSize();
int i;
for (i = 0; i < mCategories.GetSize(); i++)
{
if (mCategories[i].Name == "Search Results")
{
NumCategories--;
break;
}
}
File.WriteU32(NumCategories);
for (i = 0; i < mCategories.GetSize(); i++)
{
if (mCategories[i].Name == "Search Results")
continue;
File.WriteString(mCategories[i].Name);
File.WriteString(mCategories[i].Keywords);
}
Sys_ProfileSaveString("Settings", "Categories", mCategoriesFile);
mCategoriesModified = false;
return true;
}
int lcPiecesLibrary::FindCategoryIndex(const String& CategoryName) const
{
for (int i = 0; i < mCategories.GetSize(); i++)
if (mCategories[i].Name == CategoryName)
return i;
return -1;
}
void lcPiecesLibrary::SetCategory(int Index, const String& Name, const String& Keywords)
{
mCategories[Index].Name = Name;
mCategories[Index].Keywords = Keywords;
SystemUpdateCategories(true);
mCategoriesModified = true;
}
void lcPiecesLibrary::AddCategory(const String& Name, const String& Keywords)
{
lcLibraryCategory& Category = mCategories.Add();
Category.Name = Name;
Category.Keywords = Keywords;
SystemUpdateCategories(true);
mCategoriesModified = true;
}
void lcPiecesLibrary::RemoveCategory(int Index)
{
mCategories.RemoveIndex(Index);
mCategoriesModified = true;
}