2013-08-09 06:57:18 +02:00
# include "lc_global.h"
# include "lc_library.h"
# include "lc_zipfile.h"
# include "lc_file.h"
# include "pieceinf.h"
# include "lc_colors.h"
# include "lc_texture.h"
# include "lc_category.h"
# include "lc_application.h"
2015-04-26 20:14:33 +02:00
# include "lc_context.h"
2015-05-09 21:54:29 +02:00
# include "lc_glextensions.h"
2016-02-29 21:13:54 +01:00
# include "lc_synth.h"
2015-02-22 03:39:15 +01:00
# include "project.h"
2013-08-09 06:57:18 +02:00
# include <ctype.h>
# include <locale.h>
2015-07-22 06:00:47 +02:00
# include <zlib.h>
2017-01-23 06:22:46 +01:00
# if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
2017-01-23 05:50:43 +01:00
# include <QtConcurrent>
2017-01-23 06:22:46 +01:00
# endif
2015-07-22 06:00:47 +02:00
# if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
# else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
# endif
2013-08-09 06:57:18 +02:00
2017-12-23 14:26:55 +01:00
# define LC_LIBRARY_CACHE_VERSION 0x0106
2013-08-09 06:57:18 +02:00
# define LC_LIBRARY_CACHE_ARCHIVE 0x0001
# define LC_LIBRARY_CACHE_DIRECTORY 0x0002
2018-01-18 00:14:24 +01:00
static lcVector2 lcCalculateTexCoord ( const lcVector3 & Position , const lcLibraryTextureMap * TextureMap )
{
2018-01-28 00:57:48 +01:00
switch ( TextureMap - > Type )
{
case lcLibraryTextureMapType : : PLANAR :
2019-03-17 21:17:11 +01:00
return lcVector2 ( lcDot3 ( Position , TextureMap - > Params . Planar . Planes [ 0 ] ) + TextureMap - > Params . Planar . Planes [ 0 ] . w , lcDot3 ( Position , TextureMap - > Params . Planar . Planes [ 1 ] ) + TextureMap - > Params . Planar . Planes [ 1 ] . w ) ;
2018-01-18 00:14:24 +01:00
2018-01-28 00:57:48 +01:00
case lcLibraryTextureMapType : : CYLINDRICAL :
{
2019-03-17 21:17:11 +01:00
const lcVector4 & FrontPlane = TextureMap - > Params . Cylindrical . FrontPlane ;
const lcVector4 & Plane1 = TextureMap - > Params . Cylindrical . Plane1 ;
const lcVector4 & Plane2 = TextureMap - > Params . Cylindrical . Plane2 ;
2018-01-28 00:57:48 +01:00
lcVector2 TexCoord ;
2018-01-18 00:14:24 +01:00
2018-02-14 00:54:55 +01:00
float DotPlane1 = lcDot ( lcVector4 ( Position , 1.0f ) , Plane1 ) ;
lcVector3 PointInPlane1 = Position - lcVector3 ( Plane1 ) * DotPlane1 ;
float DotFrontPlane = lcDot ( lcVector4 ( PointInPlane1 , 1.0f ) , FrontPlane ) ;
float DotPlane2 = lcDot ( lcVector4 ( PointInPlane1 , 1.0f ) , Plane2 ) ;
2018-01-18 00:14:24 +01:00
2018-02-14 00:54:55 +01:00
float Angle1 = atan2f ( DotPlane2 , DotFrontPlane ) / LC_PI * TextureMap - > Angle1 ;
2018-02-14 01:16:22 +01:00
TexCoord . x = lcClamp ( 0.5f + 0.5f * Angle1 , 0.0f , 1.0f ) ;
2018-01-18 00:14:24 +01:00
2019-03-17 21:17:11 +01:00
TexCoord . y = DotPlane1 / TextureMap - > Params . Cylindrical . UpLength ;
2018-01-28 00:57:48 +01:00
return TexCoord ;
}
2018-01-18 00:14:24 +01:00
2018-01-28 00:57:48 +01:00
case lcLibraryTextureMapType : : SPHERICAL :
{
2019-03-17 21:17:11 +01:00
const lcVector4 & FrontPlane = TextureMap - > Params . Spherical . FrontPlane ;
const lcVector3 & Center = TextureMap - > Params . Spherical . Center ;
const lcVector4 & Plane1 = TextureMap - > Params . Spherical . Plane1 ;
const lcVector4 & Plane2 = TextureMap - > Params . Spherical . Plane2 ;
2018-01-28 00:57:48 +01:00
lcVector2 TexCoord ;
lcVector3 VertexDir = Position - Center ;
float DotPlane1 = lcDot ( lcVector4 ( Position , 1.0f ) , Plane1 ) ;
lcVector3 PointInPlane1 = Position - lcVector3 ( Plane1 ) * DotPlane1 ;
float DotFrontPlane = lcDot ( lcVector4 ( PointInPlane1 , 1.0f ) , FrontPlane ) ;
float DotPlane2 = lcDot ( lcVector4 ( PointInPlane1 , 1.0f ) , Plane2 ) ;
float Angle1 = atan2f ( DotPlane2 , DotFrontPlane ) / LC_PI * TextureMap - > Angle1 ;
TexCoord . x = 0.5f + 0.5f * Angle1 ;
float Angle2 = asinf ( DotPlane1 / lcLength ( VertexDir ) ) / LC_PI * TextureMap - > Angle2 ;
TexCoord . y = 0.5f - Angle2 ;
return TexCoord ;
}
}
return lcVector2 ( 0.0f , 0.0f ) ;
2018-01-18 00:14:24 +01:00
}
2013-08-09 06:57:18 +02:00
lcPiecesLibrary : : lcPiecesLibrary ( )
2017-01-23 04:28:05 +01:00
: mLoadMutex ( QMutex : : Recursive )
2013-08-09 06:57:18 +02:00
{
2015-07-22 06:00:47 +02:00
# if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
QStringList cachePathList = QStandardPaths : : standardLocations ( QStandardPaths : : CacheLocation ) ;
mCachePath = cachePathList . first ( ) ;
# else
mCachePath = QDesktopServices : : storageLocation ( QDesktopServices : : CacheLocation ) ;
# endif
QDir Dir ;
Dir . mkpath ( mCachePath ) ;
2013-08-09 06:57:18 +02:00
mNumOfficialPieces = 0 ;
2017-04-14 02:26:40 +02:00
mZipFiles [ LC_ZIPFILE_OFFICIAL ] = nullptr ;
mZipFiles [ LC_ZIPFILE_UNOFFICIAL ] = nullptr ;
2015-04-26 20:14:33 +02:00
mBuffersDirty = false ;
2017-03-19 21:12:24 +01:00
mHasUnofficial = false ;
2017-11-25 21:57:41 +01:00
mCancelLoading = false ;
2013-08-09 06:57:18 +02:00
}
lcPiecesLibrary : : ~ lcPiecesLibrary ( )
{
2017-01-23 04:28:05 +01:00
mLoadMutex . lock ( ) ;
mLoadQueue . clear ( ) ;
mLoadMutex . unlock ( ) ;
2017-11-25 21:57:41 +01:00
mCancelLoading = true ;
2017-01-23 04:28:05 +01:00
WaitForLoadQueue ( ) ;
2013-08-09 06:57:18 +02:00
Unload ( ) ;
}
void lcPiecesLibrary : : Unload ( )
{
2018-02-22 02:27:24 +01:00
for ( const auto & PieceIt : mPieces )
2017-07-24 04:35:18 +02:00
delete PieceIt . second ;
mPieces . clear ( ) ;
2013-08-09 06:57:18 +02:00
2018-02-22 02:27:24 +01:00
for ( const auto & PrimitiveIt : mPrimitives )
2017-07-24 01:19:09 +02:00
delete PrimitiveIt . second ;
mPrimitives . clear ( ) ;
2013-08-09 06:57:18 +02:00
for ( int TextureIdx = 0 ; TextureIdx < mTextures . GetSize ( ) ; TextureIdx + + )
delete mTextures [ TextureIdx ] ;
mTextures . RemoveAll ( ) ;
mNumOfficialPieces = 0 ;
2014-05-08 00:58:59 +02:00
delete mZipFiles [ LC_ZIPFILE_OFFICIAL ] ;
2017-04-14 02:26:40 +02:00
mZipFiles [ LC_ZIPFILE_OFFICIAL ] = nullptr ;
2014-05-08 00:58:59 +02:00
delete mZipFiles [ LC_ZIPFILE_UNOFFICIAL ] ;
2017-04-14 02:26:40 +02:00
mZipFiles [ LC_ZIPFILE_UNOFFICIAL ] = nullptr ;
2013-08-09 06:57:18 +02:00
}
2015-01-07 17:52:42 +01:00
void lcPiecesLibrary : : RemoveTemporaryPieces ( )
{
2017-01-23 04:28:05 +01:00
QMutexLocker LoadLock ( & mLoadMutex ) ;
2017-07-24 04:35:18 +02:00
for ( auto PieceIt = mPieces . begin ( ) ; PieceIt ! = mPieces . end ( ) ; )
2015-01-07 17:52:42 +01:00
{
2017-07-24 04:35:18 +02:00
PieceInfo * Info = PieceIt - > second ;
2015-01-07 17:52:42 +01:00
2017-07-24 04:35:18 +02:00
if ( Info - > IsTemporary ( ) & & Info - > GetRefCount ( ) = = 0 )
2015-01-07 17:52:42 +01:00
{
2017-07-24 04:35:18 +02:00
PieceIt = mPieces . erase ( PieceIt ) ;
2015-01-07 17:52:42 +01:00
delete Info ;
}
2017-07-24 04:35:18 +02:00
else
PieceIt + + ;
2015-01-07 17:52:42 +01:00
}
}
2015-02-22 03:39:15 +01:00
void lcPiecesLibrary : : RemovePiece ( PieceInfo * Info )
{
2017-07-24 04:35:18 +02:00
for ( auto PieceIt = mPieces . begin ( ) ; PieceIt ! = mPieces . end ( ) ; PieceIt + + )
{
if ( PieceIt - > second = = Info )
{
mPieces . erase ( PieceIt ) ;
break ;
}
}
2015-02-22 03:39:15 +01:00
delete Info ;
}
2017-07-24 04:35:18 +02:00
void lcPiecesLibrary : : RenamePiece ( PieceInfo * Info , const char * NewName )
{
2017-07-27 18:21:55 +02:00
for ( auto PieceIt = mPieces . begin ( ) ; PieceIt ! = mPieces . end ( ) ; PieceIt + + )
{
if ( PieceIt - > second = = Info )
{
mPieces . erase ( PieceIt ) ;
break ;
}
}
strncpy ( Info - > mFileName , NewName , sizeof ( Info - > mFileName ) ) ;
Info - > mFileName [ sizeof ( Info - > mFileName ) - 1 ] = 0 ;
strncpy ( Info - > m_strDescription , NewName , sizeof ( Info - > m_strDescription ) ) ;
Info - > m_strDescription [ sizeof ( Info - > m_strDescription ) - 1 ] = 0 ;
char PieceName [ LC_PIECE_NAME_LEN ] ;
strcpy ( PieceName , Info - > mFileName ) ;
strupr ( PieceName ) ;
mPieces [ PieceName ] = Info ;
2017-07-24 04:35:18 +02:00
}
2016-11-26 02:12:19 +01:00
PieceInfo * lcPiecesLibrary : : FindPiece ( const char * PieceName , Project * CurrentProject , bool CreatePlaceholder , bool SearchProjectFolder )
2013-08-09 06:57:18 +02:00
{
2016-11-26 02:12:19 +01:00
QString ProjectPath ;
if ( SearchProjectFolder )
{
QString FileName = CurrentProject - > GetFileName ( ) ;
if ( ! FileName . isEmpty ( ) )
ProjectPath = QFileInfo ( FileName ) . absolutePath ( ) ;
}
2017-07-27 18:21:55 +02:00
char CleanName [ LC_PIECE_NAME_LEN ] ;
const char * Src = PieceName ;
char * Dst = CleanName ;
while ( * Src & & Dst - CleanName ! = sizeof ( CleanName ) )
{
if ( * Src = = ' \\ ' )
* Dst = ' / ' ;
else if ( * Src > = ' a ' & & * Src < = ' z ' )
* Dst = * Src + ' A ' - ' a ' ;
else
* Dst = * Src ;
Src + + ;
Dst + + ;
}
* Dst = 0 ;
const auto PieceIt = mPieces . find ( CleanName ) ;
2015-02-22 03:39:15 +01:00
2017-07-24 04:35:18 +02:00
if ( PieceIt ! = mPieces . end ( ) )
{
PieceInfo * Info = PieceIt - > second ;
2015-02-22 03:39:15 +01:00
2017-07-24 04:35:18 +02:00
if ( ( ! CurrentProject | | ! Info - > IsModel ( ) | | CurrentProject - > GetModels ( ) . FindIndex ( Info - > GetModel ( ) ) ! = - 1 ) & & ( ! ProjectPath . isEmpty ( ) | | ! Info - > IsProject ( ) ) )
return Info ;
2015-02-22 03:39:15 +01:00
}
2013-08-09 06:57:18 +02:00
2016-11-26 02:12:19 +01:00
if ( ! ProjectPath . isEmpty ( ) )
{
QFileInfo ProjectFile = QFileInfo ( ProjectPath + QDir : : separator ( ) + PieceName ) ;
if ( ProjectFile . isFile ( ) )
{
Project * NewProject = new Project ( ) ;
if ( NewProject - > Load ( ProjectFile . absoluteFilePath ( ) ) )
{
PieceInfo * Info = new PieceInfo ( ) ;
2017-07-27 18:21:55 +02:00
Info - > CreateProject ( NewProject , PieceName ) ;
mPieces [ CleanName ] = Info ;
2016-11-26 02:12:19 +01:00
return Info ;
}
else
delete NewProject ;
}
}
2014-12-24 16:52:52 +01:00
if ( CreatePlaceholder )
{
PieceInfo * Info = new PieceInfo ( ) ;
2013-08-09 06:57:18 +02:00
2014-12-24 16:52:52 +01:00
Info - > CreatePlaceholder ( PieceName ) ;
2017-07-27 18:21:55 +02:00
mPieces [ CleanName ] = Info ;
2013-08-09 06:57:18 +02:00
2014-12-24 16:52:52 +01:00
return Info ;
}
2013-08-09 06:57:18 +02:00
2017-04-14 02:26:40 +02:00
return nullptr ;
2013-08-09 06:57:18 +02:00
}
2017-07-02 02:12:09 +02:00
lcTexture * lcPiecesLibrary : : FindTexture ( const char * TextureName , Project * CurrentProject , bool SearchProjectFolder )
2013-08-09 06:57:18 +02:00
{
for ( int TextureIdx = 0 ; TextureIdx < mTextures . GetSize ( ) ; TextureIdx + + )
if ( ! strcmp ( TextureName , mTextures [ TextureIdx ] - > mName ) )
return mTextures [ TextureIdx ] ;
2017-07-02 02:12:09 +02:00
QString ProjectPath ;
if ( SearchProjectFolder )
{
QString FileName = CurrentProject - > GetFileName ( ) ;
if ( ! FileName . isEmpty ( ) )
ProjectPath = QFileInfo ( FileName ) . absolutePath ( ) ;
}
if ( ! ProjectPath . isEmpty ( ) )
{
QFileInfo TextureFile = QFileInfo ( ProjectPath + QDir : : separator ( ) + TextureName + " .png " ) ;
if ( TextureFile . isFile ( ) )
{
lcTexture * Texture = lcLoadTexture ( TextureFile . absoluteFilePath ( ) , LC_TEXTURE_WRAPU | LC_TEXTURE_WRAPV ) ;
if ( Texture )
{
mTextures . Add ( Texture ) ;
return Texture ;
}
}
}
2017-04-14 02:26:40 +02:00
return nullptr ;
2013-08-09 06:57:18 +02:00
}
2017-11-25 05:00:16 +01:00
bool lcPiecesLibrary : : Load ( const QString & LibraryPath , bool ShowProgress )
2013-08-09 06:57:18 +02:00
{
2014-05-08 00:58:59 +02:00
Unload ( ) ;
if ( OpenArchive ( LibraryPath , LC_ZIPFILE_OFFICIAL ) )
2013-08-09 06:57:18 +02:00
{
lcMemFile ColorFile ;
2014-05-08 00:58:59 +02:00
if ( ! mZipFiles [ LC_ZIPFILE_OFFICIAL ] - > ExtractFile ( " ldraw/ldconfig.ldr " , ColorFile ) | | ! lcLoadColorFile ( ColorFile ) )
2013-08-09 06:57:18 +02:00
lcLoadDefaultColors ( ) ;
2017-05-29 22:31:24 +02:00
mLibraryDir = QFileInfo ( LibraryPath ) . absoluteDir ( ) ;
QString UnofficialFileName = mLibraryDir . absoluteFilePath ( QLatin1String ( " ldrawunf.zip " ) ) ;
2014-05-08 00:58:59 +02:00
2016-12-22 01:49:45 +01:00
if ( ! OpenArchive ( UnofficialFileName , LC_ZIPFILE_UNOFFICIAL ) )
2017-05-29 22:31:24 +02:00
UnofficialFileName . clear ( ) ;
2016-12-22 01:49:45 +01:00
2015-07-22 06:00:47 +02:00
ReadArchiveDescriptions ( LibraryPath , UnofficialFileName ) ;
2013-08-09 06:57:18 +02:00
}
else
{
2017-05-29 22:31:24 +02:00
mLibraryDir = LibraryPath ;
2013-08-09 06:57:18 +02:00
2017-11-25 05:00:16 +01:00
if ( OpenDirectory ( mLibraryDir , ShowProgress ) )
2013-08-09 06:57:18 +02:00
{
2017-05-29 22:31:24 +02:00
lcDiskFile ColorFile ( mLibraryDir . absoluteFilePath ( QLatin1String ( " ldconfig.ldr " ) ) ) ;
2013-08-09 06:57:18 +02:00
2017-05-29 22:31:24 +02:00
if ( ! ColorFile . Open ( QIODevice : : ReadOnly ) | | ! lcLoadColorFile ( ColorFile ) )
2019-05-18 19:49:48 +02:00
{
ColorFile . SetFileName ( mLibraryDir . absoluteFilePath ( QLatin1String ( " LDConfig.ldr " ) ) ) ;
if ( ! ColorFile . Open ( QIODevice : : ReadOnly ) | | ! lcLoadColorFile ( ColorFile ) )
lcLoadDefaultColors ( ) ;
}
2013-08-09 06:57:18 +02:00
}
else
return false ;
}
lcLoadDefaultCategories ( ) ;
2016-02-29 21:13:54 +01:00
lcSynthInit ( ) ;
2013-08-09 06:57:18 +02:00
return true ;
}
2017-05-29 22:31:24 +02:00
bool lcPiecesLibrary : : OpenArchive ( const QString & FileName , lcZipFileType ZipFileType )
2014-09-11 21:55:34 +02:00
{
2017-05-29 22:31:24 +02:00
lcDiskFile * File = new lcDiskFile ( FileName ) ;
2014-09-11 21:55:34 +02:00
2017-05-29 22:31:24 +02:00
if ( ! File - > Open ( QIODevice : : ReadOnly ) | | ! OpenArchive ( File , FileName , ZipFileType ) )
2014-09-11 21:55:34 +02:00
{
delete File ;
return false ;
}
return true ;
}
2017-05-29 22:31:24 +02:00
bool lcPiecesLibrary : : OpenArchive ( lcFile * File , const QString & FileName , lcZipFileType ZipFileType )
2013-08-09 06:57:18 +02:00
{
2014-05-08 00:58:59 +02:00
lcZipFile * ZipFile = new lcZipFile ( ) ;
2013-08-09 06:57:18 +02:00
2014-09-11 21:55:34 +02:00
if ( ! ZipFile - > OpenRead ( File ) )
2013-08-09 06:57:18 +02:00
{
2014-05-08 00:58:59 +02:00
delete ZipFile ;
2013-08-09 06:57:18 +02:00
return false ;
}
2014-05-08 00:58:59 +02:00
mZipFiles [ ZipFileType ] = ZipFile ;
if ( ZipFileType = = LC_ZIPFILE_OFFICIAL )
2017-05-29 22:31:24 +02:00
mLibraryFileName = FileName ;
2014-05-08 00:58:59 +02:00
else
2017-05-29 22:31:24 +02:00
mUnofficialFileName = FileName ;
2013-08-09 06:57:18 +02:00
2014-05-08 00:58:59 +02:00
for ( int FileIdx = 0 ; FileIdx < ZipFile - > mFiles . GetSize ( ) ; FileIdx + + )
2013-08-09 06:57:18 +02:00
{
2014-05-08 00:58:59 +02:00
lcZipFileInfo & FileInfo = ZipFile - > mFiles [ FileIdx ] ;
char NameBuffer [ LC_PIECE_NAME_LEN ] ;
char * Name = NameBuffer ;
2013-08-09 06:57:18 +02:00
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 ;
2017-07-27 18:21:55 +02:00
* Dst = 0 ;
2013-08-09 06:57:18 +02:00
Dst - = 4 ;
if ( memcmp ( Dst , " .DAT " , 4 ) )
{
2017-12-22 13:38:47 +01:00
if ( ! memcmp ( Dst , " .PNG " , 4 ) )
2013-08-09 06:57:18 +02:00
{
2017-12-22 13:38:47 +01:00
if ( ( ZipFileType = = LC_ZIPFILE_OFFICIAL & & ! memcmp ( Name , " LDRAW/PARTS/TEXTURES/ " , 21 ) ) | |
( ZipFileType = = LC_ZIPFILE_UNOFFICIAL & & ! memcmp ( Name , " PARTS/TEXTURES/ " , 15 ) ) )
{
lcTexture * Texture = new lcTexture ( ) ;
mTextures . Add ( Texture ) ;
2013-08-09 06:57:18 +02:00
2017-12-22 13:38:47 +01:00
* Dst = 0 ;
strncpy ( Texture - > mName , Name + ( ZipFileType = = LC_ZIPFILE_OFFICIAL ? 21 : 15 ) , sizeof ( Texture - > mName ) ) ;
Texture - > mName [ sizeof ( Texture - > mName ) - 1 ] = 0 ;
}
2013-08-09 06:57:18 +02:00
}
continue ;
}
2014-05-08 00:58:59 +02:00
if ( ZipFileType = = LC_ZIPFILE_OFFICIAL )
{
if ( memcmp ( Name , " LDRAW/ " , 6 ) )
continue ;
Name + = 6 ;
}
2013-08-09 06:57:18 +02:00
2014-05-08 00:58:59 +02:00
if ( ! memcmp ( Name , " PARTS/ " , 6 ) )
2013-08-09 06:57:18 +02:00
{
2014-05-08 00:58:59 +02:00
Name + = 6 ;
if ( memcmp ( Name , " S/ " , 2 ) )
2013-08-09 06:57:18 +02:00
{
2017-04-14 02:26:40 +02:00
PieceInfo * Info = FindPiece ( Name , nullptr , false , false ) ;
2014-05-08 00:58:59 +02:00
if ( ! Info )
{
Info = new PieceInfo ( ) ;
2013-08-09 06:57:18 +02:00
2017-07-27 18:21:55 +02:00
strncpy ( Info - > mFileName , FileInfo . file_name + ( Name - NameBuffer ) , sizeof ( Info - > mFileName ) ) ;
Info - > mFileName [ sizeof ( Info - > mFileName ) - 1 ] = 0 ;
2017-07-24 04:35:18 +02:00
2017-07-27 18:21:55 +02:00
mPieces [ Name ] = Info ;
2014-05-08 00:58:59 +02:00
}
Info - > SetZipFile ( ZipFileType , FileIdx ) ;
2013-08-09 06:57:18 +02:00
}
else
{
2017-07-24 01:19:09 +02:00
lcLibraryPrimitive * Primitive = FindPrimitive ( Name ) ;
2014-05-08 00:58:59 +02:00
2017-07-24 01:19:09 +02:00
if ( ! Primitive )
2019-06-02 04:54:09 +02:00
mPrimitives [ Name ] = new lcLibraryPrimitive ( QString ( ) , FileInfo . file_name + ( Name - NameBuffer ) , ZipFileType , FileIdx , false , true ) ;
2014-05-08 00:58:59 +02:00
else
2017-07-24 01:19:09 +02:00
Primitive - > SetZipFile ( ZipFileType , FileIdx ) ;
2013-08-09 06:57:18 +02:00
}
}
2014-05-08 00:58:59 +02:00
else if ( ! memcmp ( Name , " P/ " , 2 ) )
2013-08-09 06:57:18 +02:00
{
2014-05-08 00:58:59 +02:00
Name + = 2 ;
2017-07-24 01:19:09 +02:00
lcLibraryPrimitive * Primitive = FindPrimitive ( Name ) ;
2014-05-08 00:58:59 +02:00
2017-07-24 01:19:09 +02:00
if ( ! Primitive )
2019-06-02 04:54:09 +02:00
mPrimitives [ Name ] = new lcLibraryPrimitive ( QString ( ) , FileInfo . file_name + ( Name - NameBuffer ) , ZipFileType , FileIdx , ( memcmp ( Name , " STU " , 3 ) = = 0 ) , false ) ;
2014-05-08 00:58:59 +02:00
else
2017-07-24 01:19:09 +02:00
Primitive - > SetZipFile ( ZipFileType , FileIdx ) ;
2013-08-09 06:57:18 +02:00
}
}
2014-05-08 00:58:59 +02:00
return true ;
}
2015-07-22 06:00:47 +02:00
void lcPiecesLibrary : : ReadArchiveDescriptions ( const QString & OfficialFileName , const QString & UnofficialFileName )
2014-05-08 00:58:59 +02:00
{
2015-07-22 06:00:47 +02:00
QFileInfo OfficialInfo ( OfficialFileName ) ;
2016-02-19 18:53:54 +01:00
QFileInfo UnofficialInfo ( UnofficialFileName ) ;
2016-12-22 01:49:45 +01:00
2015-07-22 06:00:47 +02:00
mArchiveCheckSum [ 0 ] = OfficialInfo . size ( ) ;
2016-09-22 17:04:51 +02:00
# if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0))
2015-07-22 06:00:47 +02:00
mArchiveCheckSum [ 1 ] = OfficialInfo . lastModified ( ) . toMSecsSinceEpoch ( ) ;
2016-09-22 17:04:51 +02:00
# else
mArchiveCheckSum [ 1 ] = OfficialInfo . lastModified ( ) . toTime_t ( ) ;
# endif
2016-12-22 01:49:45 +01:00
if ( ! UnofficialFileName . isEmpty ( ) )
{
mArchiveCheckSum [ 2 ] = UnofficialInfo . size ( ) ;
2016-09-22 17:04:51 +02:00
# if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0))
2016-12-22 01:49:45 +01:00
mArchiveCheckSum [ 3 ] = UnofficialInfo . lastModified ( ) . toMSecsSinceEpoch ( ) ;
2016-09-22 17:04:51 +02:00
# else
2016-12-22 01:49:45 +01:00
mArchiveCheckSum [ 3 ] = UnofficialInfo . lastModified ( ) . toTime_t ( ) ;
2016-09-22 17:04:51 +02:00
# endif
2016-12-22 01:49:45 +01:00
}
else
{
mArchiveCheckSum [ 2 ] = 0 ;
mArchiveCheckSum [ 3 ] = 0 ;
}
2015-07-22 06:00:47 +02:00
QString IndexFileName = QFileInfo ( QDir ( mCachePath ) , QLatin1String ( " index " ) ) . absoluteFilePath ( ) ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
if ( ! LoadCacheIndex ( IndexFileName ) )
2013-08-09 06:57:18 +02:00
{
lcMemFile PieceFile ;
2018-02-22 02:27:24 +01:00
for ( const auto & PieceIt : mPieces )
2013-08-09 06:57:18 +02:00
{
2017-07-24 04:35:18 +02:00
PieceInfo * Info = PieceIt . second ;
2013-08-09 06:57:18 +02:00
2014-05-08 00:58:59 +02:00
mZipFiles [ Info - > mZipFileType ] - > ExtractFile ( Info - > mZipFileIndex , PieceFile , 256 ) ;
2013-08-09 06:57:18 +02:00
PieceFile . Seek ( 0 , SEEK_END ) ;
PieceFile . WriteU8 ( 0 ) ;
char * Src = ( char * ) PieceFile . mBuffer + 2 ;
char * Dst = Info - > m_strDescription ;
for ( ; ; )
{
if ( * Src ! = ' \r ' & & * Src ! = ' \n ' & & * Src & & Dst - Info - > m_strDescription < ( int ) sizeof ( Info - > m_strDescription ) - 1 )
{
* Dst + + = * Src + + ;
continue ;
}
* Dst = 0 ;
break ;
}
}
2015-07-22 06:00:47 +02:00
2017-11-27 04:21:54 +01:00
SaveArchiveCacheIndex ( IndexFileName ) ;
2013-08-09 06:57:18 +02:00
}
}
2017-11-25 05:00:16 +01:00
bool lcPiecesLibrary : : OpenDirectory ( const QDir & LibraryDir , bool ShowProgress )
2013-08-09 06:57:18 +02:00
{
2017-11-27 04:21:54 +01:00
const QLatin1String BaseFolders [ LC_NUM_FOLDERTYPES ] = { QLatin1String ( " unofficial/ " ) , QLatin1String ( " " ) } ;
2017-11-25 03:19:29 +01:00
const int NumBaseFolders = sizeof ( BaseFolders ) / sizeof ( BaseFolders [ 0 ] ) ;
2017-03-19 21:12:24 +01:00
2017-11-27 04:21:54 +01:00
QFileInfoList FileLists [ NumBaseFolders ] ;
2013-08-09 06:57:18 +02:00
2017-11-27 04:21:54 +01:00
for ( unsigned int BaseFolderIdx = 0 ; BaseFolderIdx < NumBaseFolders ; BaseFolderIdx + + )
{
QString ParstPath = QDir ( LibraryDir . absoluteFilePath ( BaseFolders [ BaseFolderIdx ] ) ) . absoluteFilePath ( QLatin1String ( " parts/ " ) ) ;
QDir Dir = QDir ( ParstPath , QLatin1String ( " *.dat " ) , QDir : : SortFlags ( QDir : : Name | QDir : : IgnoreCase ) , QDir : : Files | QDir : : Hidden | QDir : : Readable ) ;
FileLists [ BaseFolderIdx ] = Dir . entryInfoList ( ) ;
2013-08-09 06:57:18 +02:00
}
2017-11-27 04:21:54 +01:00
if ( FileLists [ LC_FOLDER_OFFICIAL ] . isEmpty ( ) )
2013-08-09 06:57:18 +02:00
return false ;
2017-11-27 04:21:54 +01:00
mHasUnofficial = ! FileLists [ LC_FOLDER_UNOFFICIAL ] . isEmpty ( ) ;
ReadDirectoryDescriptions ( FileLists , ShowProgress ) ;
2017-03-20 21:03:31 +01:00
for ( unsigned int BaseFolderIdx = 0 ; BaseFolderIdx < sizeof ( BaseFolders ) / sizeof ( BaseFolders [ 0 ] ) ; BaseFolderIdx + + )
2013-08-09 06:57:18 +02:00
{
2019-06-02 04:54:09 +02:00
const char * PrimitiveDirectories [ ] = { " p/ " , " parts/s/ " } ;
2017-03-19 21:12:24 +01:00
bool SubFileDirectories [ ] = { false , false , true } ;
2017-05-29 22:31:24 +02:00
QDir BaseDir ( LibraryDir . absoluteFilePath ( QLatin1String ( BaseFolders [ BaseFolderIdx ] ) ) ) ;
2013-08-09 06:57:18 +02:00
2017-03-19 21:12:24 +01:00
for ( int DirectoryIdx = 0 ; DirectoryIdx < ( int ) ( sizeof ( PrimitiveDirectories ) / sizeof ( PrimitiveDirectories [ 0 ] ) ) ; DirectoryIdx + + )
2013-08-09 06:57:18 +02:00
{
2019-06-02 04:54:09 +02:00
QString ChildPath = BaseDir . absoluteFilePath ( QLatin1String ( PrimitiveDirectories [ DirectoryIdx ] ) ) ;
QDirIterator DirIterator ( ChildPath , QStringList ( ) < < QLatin1String ( " *.dat " ) , QDir : : Files | QDir : : Hidden | QDir : : Readable , QDirIterator : : Subdirectories ) ;
2013-08-09 06:57:18 +02:00
2019-06-02 04:54:09 +02:00
while ( DirIterator . hasNext ( ) )
2013-08-09 06:57:18 +02:00
{
2017-03-19 21:12:24 +01:00
char Name [ LC_PIECE_NAME_LEN ] ;
2019-06-02 04:54:09 +02:00
QString FileName = DirIterator . next ( ) ;
QByteArray FileString = BaseDir . relativeFilePath ( FileName ) . toLatin1 ( ) ;
const char * Src = strchr ( FileString , ' / ' ) + 1 ;
char * Dst = Name ;
2013-08-09 06:57:18 +02:00
2017-03-19 21:12:24 +01:00
while ( * Src & & Dst - Name < ( int ) sizeof ( Name ) )
{
if ( * Src > = ' a ' & & * Src < = ' z ' )
* Dst = * Src + ' A ' - ' a ' ;
else if ( * Src = = ' \\ ' )
* Dst = ' / ' ;
else
* Dst = * Src ;
2013-08-09 06:57:18 +02:00
2017-03-19 21:12:24 +01:00
Src + + ;
Dst + + ;
}
2017-07-28 01:09:38 +02:00
* Dst = 0 ;
2013-08-09 06:57:18 +02:00
2017-03-19 21:12:24 +01:00
if ( Dst - Name < = 4 )
continue ;
Dst - = 4 ;
if ( memcmp ( Dst , " .DAT " , 4 ) )
continue ;
2017-07-24 01:19:09 +02:00
if ( mHasUnofficial & & IsPrimitive ( Name ) )
2017-03-19 21:12:24 +01:00
continue ;
if ( BaseFolderIdx = = 0 )
mHasUnofficial = true ;
bool SubFile = SubFileDirectories [ DirectoryIdx ] ;
2019-06-02 04:54:09 +02:00
mPrimitives [ Name ] = new lcLibraryPrimitive ( std : : move ( FileName ) , strchr ( FileString , ' / ' ) + 1 , LC_NUM_ZIPFILES , 0 , ! SubFile & & ( memcmp ( Name , " STU " , 3 ) = = 0 ) , SubFile ) ;
2017-03-19 21:12:24 +01:00
}
2013-08-09 06:57:18 +02:00
}
}
2017-05-29 22:31:24 +02:00
QDir Dir ( LibraryDir . absoluteFilePath ( QLatin1String ( " parts/textures/ " ) ) , QLatin1String ( " *.png " ) , QDir : : SortFlags ( QDir : : Name | QDir : : IgnoreCase ) , QDir : : Files | QDir : : Hidden | QDir : : Readable ) ;
2017-02-09 02:41:14 +01:00
QStringList FileList = Dir . entryList ( ) ;
2013-08-09 06:57:18 +02:00
2017-02-09 02:41:14 +01:00
mTextures . AllocGrow ( FileList . size ( ) ) ;
2013-08-09 06:57:18 +02:00
2017-02-09 02:41:14 +01:00
for ( int FileIdx = 0 ; FileIdx < FileList . size ( ) ; FileIdx + + )
2013-08-09 06:57:18 +02:00
{
char Name [ LC_MAXPATH ] ;
2017-02-09 02:41:14 +01:00
QByteArray FileString = FileList [ FileIdx ] . toLatin1 ( ) ;
const char * Src = FileString ;
2013-08-09 06:57:18 +02:00
char * Dst = Name ;
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 , " .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 ;
}
2017-11-27 04:21:54 +01:00
void lcPiecesLibrary : : ReadDirectoryDescriptions ( const QFileInfoList ( & FileLists ) [ LC_NUM_FOLDERTYPES ] , bool ShowProgress )
{
QString IndexFileName = QFileInfo ( QDir ( mCachePath ) , QLatin1String ( " index " ) ) . absoluteFilePath ( ) ;
lcMemFile IndexFile ;
std : : vector < const char * > CachedDescriptions ;
if ( ReadDirectoryCacheFile ( IndexFileName , IndexFile ) )
{
QString LibraryPath = IndexFile . ReadQString ( ) ;
if ( LibraryPath = = mLibraryDir . absolutePath ( ) )
{
int NumDescriptions = IndexFile . ReadU32 ( ) ;
CachedDescriptions . reserve ( NumDescriptions ) ;
while ( NumDescriptions - - )
{
const char * FileName = ( const char * ) IndexFile . mBuffer + IndexFile . GetPosition ( ) ;
CachedDescriptions . push_back ( FileName ) ;
IndexFile . Seek ( strlen ( FileName ) + 1 , SEEK_CUR ) ;
const char * Description = ( const char * ) IndexFile . mBuffer + IndexFile . GetPosition ( ) ;
IndexFile . Seek ( strlen ( Description ) + 1 , SEEK_CUR ) ;
IndexFile . Seek ( 4 + 1 + 8 , SEEK_CUR ) ;
}
}
}
for ( int FolderIdx = 0 ; FolderIdx < LC_NUM_FOLDERTYPES ; FolderIdx + + )
{
const QFileInfoList & FileList = FileLists [ FolderIdx ] ;
for ( int FileIdx = 0 ; FileIdx < FileList . size ( ) ; FileIdx + + )
{
char Name [ LC_PIECE_NAME_LEN ] ;
QByteArray FileString = FileList [ FileIdx ] . fileName ( ) . toLatin1 ( ) ;
const char * Src = FileString ;
char * Dst = Name ;
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 + + ;
}
* Dst = 0 ;
if ( FolderIdx = = LC_FOLDER_OFFICIAL & & mHasUnofficial & & mPieces . find ( Name ) ! = mPieces . end ( ) )
continue ;
PieceInfo * Info = new PieceInfo ( ) ;
strncpy ( Info - > mFileName , FileString , sizeof ( Info - > mFileName ) ) ;
Info - > mFileName [ sizeof ( Info - > mFileName ) - 1 ] = 0 ;
Info - > mFolderType = FolderIdx ;
Info - > mFolderIndex = FileIdx ;
mPieces [ Name ] = Info ;
}
}
QAtomicInt FilesLoaded ;
bool Modified = false ;
auto ReadDescriptions = [ & FileLists , & CachedDescriptions , & FilesLoaded , & Modified ] ( const std : : pair < std : : string , PieceInfo * > & Entry )
{
PieceInfo * Info = Entry . second ;
FilesLoaded . ref ( ) ;
lcDiskFile PieceFile ( FileLists [ Info - > mFolderType ] [ Info - > mFolderIndex ] . absoluteFilePath ( ) ) ;
char Line [ 1024 ] ;
if ( ! CachedDescriptions . empty ( ) )
{
auto DescriptionCompare = [ ] ( const void * Key , const void * Element )
{
return strcmp ( ( const char * ) Key , * ( const char * * ) Element ) ;
} ;
void * CachedDescription = bsearch ( Info - > mFileName , & CachedDescriptions . front ( ) , CachedDescriptions . size ( ) , sizeof ( char * ) , DescriptionCompare ) ;
if ( CachedDescription )
{
const char * FileName = * ( const char * * ) CachedDescription ;
const char * Description = FileName + strlen ( FileName ) + 1 ;
2018-02-01 21:48:31 +01:00
uint64_t CachedFileTime = * ( uint64_t * ) ( Description + strlen ( Description ) + 1 + 4 + 1 ) ;
# if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0))
quint64 FileTime = FileLists [ Info - > mFolderType ] [ Info - > mFolderIndex ] . lastModified ( ) . toMSecsSinceEpoch ( ) ;
# else
quint64 FileTime = FileLists [ Info - > mFolderType ] [ Info - > mFolderIndex ] . lastModified ( ) . toTime_t ( ) ;
# endif
if ( FileTime = = CachedFileTime )
{
strcpy ( Info - > m_strDescription , Description ) ;
return ;
}
2017-11-27 04:21:54 +01:00
}
}
if ( ! PieceFile . Open ( QIODevice : : ReadOnly ) | | ! PieceFile . ReadLine ( Line , sizeof ( Line ) ) )
{
strcpy ( Info - > m_strDescription , " Unknown " ) ;
return ;
}
const char * Src = Line + 2 ;
char * Dst = Info - > m_strDescription ;
for ( ; ; )
{
if ( * Src ! = ' \r ' & & * Src ! = ' \n ' & & * Src & & Dst - Info - > m_strDescription < ( int ) sizeof ( Info - > m_strDescription ) - 1 )
{
* Dst + + = * Src + + ;
continue ;
}
* Dst = 0 ;
break ;
}
Modified = true ;
} ;
QProgressDialog * ProgressDialog = new QProgressDialog ( nullptr ) ;
ProgressDialog - > setWindowFlags ( ProgressDialog - > windowFlags ( ) & ~ Qt : : WindowCloseButtonHint ) ;
ProgressDialog - > setWindowTitle ( tr ( " Initializing " ) ) ;
ProgressDialog - > setLabelText ( tr ( " Loading Parts Library " ) ) ;
2019-05-18 20:33:27 +02:00
ProgressDialog - > setMaximum ( ( int ) mPieces . size ( ) ) ;
2017-11-27 04:21:54 +01:00
ProgressDialog - > setMinimum ( 0 ) ;
ProgressDialog - > setValue ( 0 ) ;
ProgressDialog - > setCancelButton ( nullptr ) ;
ProgressDialog - > setAutoReset ( false ) ;
if ( ShowProgress )
ProgressDialog - > show ( ) ;
QFuture < void > LoadFuture = QtConcurrent : : map ( mPieces , ReadDescriptions ) ;
while ( ! LoadFuture . isFinished ( ) )
{
2017-12-10 19:13:58 +01:00
# if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0) || QT_VERSION < QT_VERSION_CHECK(5, 0, 0) )
2017-11-27 04:21:54 +01:00
ProgressDialog - > setValue ( FilesLoaded ) ;
2017-12-10 19:13:58 +01:00
# else
ProgressDialog - > setValue ( FilesLoaded . load ( ) ) ;
# endif
2017-11-27 04:21:54 +01:00
QApplication : : processEvents ( QEventLoop : : ExcludeUserInputEvents ) ;
}
2017-12-10 19:13:58 +01:00
# if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0) || QT_VERSION < QT_VERSION_CHECK(5, 0, 0) )
2017-11-27 04:21:54 +01:00
ProgressDialog - > setValue ( FilesLoaded ) ;
2017-12-10 19:13:58 +01:00
# else
ProgressDialog - > setValue ( FilesLoaded . load ( ) ) ;
# endif
2017-11-27 04:21:54 +01:00
QApplication : : processEvents ( QEventLoop : : ExcludeUserInputEvents ) ;
ProgressDialog - > deleteLater ( ) ;
if ( Modified )
{
2019-05-18 20:33:27 +02:00
lcMemFile NewIndexFile ;
2017-11-27 04:21:54 +01:00
2019-05-18 20:33:27 +02:00
NewIndexFile . WriteQString ( mLibraryDir . absolutePath ( ) ) ;
2017-11-27 04:21:54 +01:00
2019-05-18 20:33:27 +02:00
NewIndexFile . WriteU32 ( ( quint32 ) mPieces . size ( ) ) ;
2017-11-27 04:21:54 +01:00
std : : vector < PieceInfo * > SortedPieces ;
SortedPieces . reserve ( mPieces . size ( ) ) ;
2018-02-22 02:27:24 +01:00
for ( const auto & PieceIt : mPieces )
2017-11-27 04:21:54 +01:00
SortedPieces . push_back ( PieceIt . second ) ;
auto PieceInfoCompare = [ ] ( PieceInfo * Info1 , PieceInfo * Info2 )
{
return strcmp ( Info1 - > mFileName , Info2 - > mFileName ) < 0 ;
} ;
std : : sort ( SortedPieces . begin ( ) , SortedPieces . end ( ) , PieceInfoCompare ) ;
for ( const PieceInfo * Info : SortedPieces )
{
2019-05-18 20:33:27 +02:00
if ( NewIndexFile . WriteBuffer ( Info - > mFileName , strlen ( Info - > mFileName ) + 1 ) = = 0 )
2017-11-27 04:21:54 +01:00
return ;
2019-05-18 20:33:27 +02:00
if ( NewIndexFile . WriteBuffer ( Info - > m_strDescription , strlen ( Info - > m_strDescription ) + 1 ) = = 0 )
2017-11-27 04:21:54 +01:00
return ;
2019-05-18 20:33:27 +02:00
NewIndexFile . WriteU32 ( Info - > mFlags ) ;
NewIndexFile . WriteU8 ( Info - > mFolderType ) ;
2017-11-27 04:21:54 +01:00
# if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0))
2017-12-02 21:22:04 +01:00
quint64 FileTime = FileLists [ Info - > mFolderType ] [ Info - > mFolderIndex ] . lastModified ( ) . toMSecsSinceEpoch ( ) ;
2017-11-27 04:21:54 +01:00
# else
2017-12-02 21:22:04 +01:00
quint64 FileTime = FileLists [ Info - > mFolderType ] [ Info - > mFolderIndex ] . lastModified ( ) . toTime_t ( ) ;
2017-11-27 04:21:54 +01:00
# endif
2018-02-01 21:48:31 +01:00
2019-05-18 20:33:27 +02:00
NewIndexFile . WriteU64 ( FileTime ) ;
2017-11-27 04:21:54 +01:00
}
2019-05-18 20:33:27 +02:00
WriteDirectoryCacheFile ( IndexFileName , NewIndexFile ) ;
2017-11-27 04:21:54 +01:00
}
}
bool lcPiecesLibrary : : ReadArchiveCacheFile ( const QString & FileName , lcMemFile & CacheFile )
2013-08-09 06:57:18 +02:00
{
2015-07-22 06:00:47 +02:00
QFile File ( FileName ) ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
if ( ! File . open ( QIODevice : : ReadOnly ) )
2013-08-09 06:57:18 +02:00
return false ;
2015-07-22 06:00:47 +02:00
quint32 CacheVersion , CacheFlags ;
if ( File . read ( ( char * ) & CacheVersion , sizeof ( CacheVersion ) ) = = - 1 | | CacheVersion ! = LC_LIBRARY_CACHE_VERSION )
2013-08-09 06:57:18 +02:00
return false ;
2015-07-22 06:00:47 +02:00
if ( File . read ( ( char * ) & CacheFlags , sizeof ( CacheFlags ) ) = = - 1 | | CacheFlags ! = LC_LIBRARY_CACHE_ARCHIVE )
return false ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
qint64 CacheCheckSum [ 4 ] ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
if ( File . read ( ( char * ) & CacheCheckSum , sizeof ( CacheCheckSum ) ) = = - 1 | | memcmp ( CacheCheckSum , mArchiveCheckSum , sizeof ( CacheCheckSum ) ) )
2013-08-09 06:57:18 +02:00
return false ;
2015-07-22 06:00:47 +02:00
quint32 UncompressedSize ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
if ( File . read ( ( char * ) & UncompressedSize , sizeof ( UncompressedSize ) ) = = - 1 )
return false ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
QByteArray CompressedData = File . readAll ( ) ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
CacheFile . SetLength ( UncompressedSize ) ;
CacheFile . Seek ( 0 , SEEK_SET ) ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
const int CHUNK = 16384 ;
int ret ;
unsigned have ;
z_stream strm ;
unsigned char in [ CHUNK ] ;
unsigned char out [ CHUNK ] ;
int pos ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
strm . zalloc = Z_NULL ;
strm . zfree = Z_NULL ;
strm . opaque = Z_NULL ;
strm . avail_in = 0 ;
strm . next_in = Z_NULL ;
pos = 0 ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
ret = inflateInit2 ( & strm , - MAX_WBITS ) ;
if ( ret ! = Z_OK )
return ret ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
do
2013-08-09 06:57:18 +02:00
{
2015-07-22 06:00:47 +02:00
strm . avail_in = lcMin ( CompressedData . size ( ) - pos , CHUNK ) ;
strm . next_in = in ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
if ( strm . avail_in = = 0 )
break ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
memcpy ( in , CompressedData . constData ( ) + pos , strm . avail_in ) ;
pos + = strm . avail_in ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
do
{
strm . avail_out = CHUNK ;
strm . next_out = out ;
ret = inflate ( & strm , Z_NO_FLUSH ) ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
switch ( ret )
{
case Z_NEED_DICT :
ret = Z_DATA_ERROR ;
2018-09-24 20:29:05 +02:00
Q_FALLTHROUGH ( ) ;
2015-07-22 06:00:47 +02:00
case Z_DATA_ERROR :
2018-09-24 20:29:05 +02:00
Q_FALLTHROUGH ( ) ;
2015-07-22 06:00:47 +02:00
case Z_MEM_ERROR :
( void ) inflateEnd ( & strm ) ;
return ret ;
}
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
have = CHUNK - strm . avail_out ;
CacheFile . WriteBuffer ( out , have ) ;
} while ( strm . avail_out = = 0 ) ;
} while ( ret ! = Z_STREAM_END ) ;
( void ) inflateEnd ( & strm ) ;
CacheFile . Seek ( 0 , SEEK_SET ) ;
return ret = = Z_STREAM_END ;
2013-08-09 06:57:18 +02:00
}
2017-11-27 04:21:54 +01:00
bool lcPiecesLibrary : : WriteArchiveCacheFile ( const QString & FileName , lcMemFile & CacheFile )
2013-08-09 06:57:18 +02:00
{
2015-07-22 06:00:47 +02:00
QFile File ( FileName ) ;
if ( ! File . open ( QIODevice : : WriteOnly ) )
2013-08-09 06:57:18 +02:00
return false ;
2015-07-22 06:00:47 +02:00
quint32 CacheVersion = LC_LIBRARY_CACHE_VERSION ;
quint32 CacheFlags = LC_LIBRARY_CACHE_ARCHIVE ;
if ( File . write ( ( char * ) & CacheVersion , sizeof ( CacheVersion ) ) = = - 1 )
return false ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
if ( File . write ( ( char * ) & CacheFlags , sizeof ( CacheFlags ) ) = = - 1 )
return false ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
if ( File . write ( ( char * ) & mArchiveCheckSum , sizeof ( mArchiveCheckSum ) ) = = - 1 )
return false ;
2013-08-09 06:57:18 +02:00
2016-02-19 18:53:54 +01:00
quint32 UncompressedSize = ( quint32 ) CacheFile . GetLength ( ) ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
if ( File . write ( ( char * ) & UncompressedSize , sizeof ( UncompressedSize ) ) = = - 1 )
return false ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
const size_t BufferSize = 16384 ;
char WriteBuffer [ BufferSize ] ;
z_stream Stream ;
2017-12-02 21:22:04 +01:00
quint32 Crc32 = 0 ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
CacheFile . Seek ( 0 , SEEK_SET ) ;
2013-08-09 06:57:18 +02:00
2019-06-03 22:23:04 +02:00
Stream . zalloc = nullptr ;
Stream . zfree = nullptr ;
Stream . opaque = nullptr ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
if ( deflateInit2 ( & Stream , Z_DEFAULT_COMPRESSION , Z_DEFLATED , - MAX_WBITS , DEF_MEM_LEVEL , Z_DEFAULT_STRATEGY ) ! = Z_OK )
return false ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
Bytef * BufferIn = CacheFile . mBuffer ;
int FlushMode ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
do
{
2016-02-19 18:53:54 +01:00
uInt Read = ( uInt ) lcMin ( CacheFile . GetLength ( ) - ( BufferIn - CacheFile . mBuffer ) , BufferSize ) ;
2015-07-22 06:00:47 +02:00
Stream . avail_in = Read ;
Stream . next_in = BufferIn ;
Crc32 = crc32 ( Crc32 , BufferIn , Read ) ;
BufferIn + = Read ;
FlushMode = ( BufferIn > = CacheFile . mBuffer + CacheFile . GetLength ( ) ) ? Z_FINISH : Z_NO_FLUSH ;
do
{
Stream . avail_out = BufferSize ;
Stream . next_out = ( Bytef * ) WriteBuffer ;
deflate ( & Stream , FlushMode ) ;
File . write ( WriteBuffer , BufferSize - Stream . avail_out ) ;
} while ( Stream . avail_out = = 0 ) ;
} while ( FlushMode ! = Z_FINISH ) ;
deflateEnd ( & Stream ) ;
return true ;
2013-08-09 06:57:18 +02:00
}
2017-11-27 04:21:54 +01:00
bool lcPiecesLibrary : : ReadDirectoryCacheFile ( const QString & FileName , lcMemFile & CacheFile )
{
QFile File ( FileName ) ;
if ( ! File . open ( QIODevice : : ReadOnly ) )
return false ;
quint32 CacheVersion , CacheFlags ;
if ( File . read ( ( char * ) & CacheVersion , sizeof ( CacheVersion ) ) = = - 1 | | CacheVersion ! = LC_LIBRARY_CACHE_VERSION )
return false ;
if ( File . read ( ( char * ) & CacheFlags , sizeof ( CacheFlags ) ) = = - 1 | | CacheFlags ! = LC_LIBRARY_CACHE_DIRECTORY )
return false ;
quint32 UncompressedSize ;
if ( File . read ( ( char * ) & UncompressedSize , sizeof ( UncompressedSize ) ) = = - 1 )
return false ;
QByteArray Data = qUncompress ( File . readAll ( ) ) ;
if ( Data . isEmpty ( ) )
return false ;
CacheFile . SetLength ( Data . size ( ) ) ;
CacheFile . Seek ( 0 , SEEK_SET ) ;
CacheFile . WriteBuffer ( Data . constData ( ) , Data . size ( ) ) ;
CacheFile . Seek ( 0 , SEEK_SET ) ;
return true ;
}
bool lcPiecesLibrary : : WriteDirectoryCacheFile ( const QString & FileName , lcMemFile & CacheFile )
{
QFile File ( FileName ) ;
if ( ! File . open ( QIODevice : : WriteOnly ) )
return false ;
quint32 CacheVersion = LC_LIBRARY_CACHE_VERSION ;
if ( File . write ( ( char * ) & CacheVersion , sizeof ( CacheVersion ) ) = = - 1 )
return false ;
quint32 CacheFlags = LC_LIBRARY_CACHE_DIRECTORY ;
if ( File . write ( ( char * ) & CacheFlags , sizeof ( CacheFlags ) ) = = - 1 )
return false ;
quint32 UncompressedSize = ( quint32 ) CacheFile . GetLength ( ) ;
if ( File . write ( ( char * ) & UncompressedSize , sizeof ( UncompressedSize ) ) = = - 1 )
return false ;
2019-05-18 20:33:27 +02:00
File . write ( qCompress ( CacheFile . mBuffer , ( int ) CacheFile . GetLength ( ) ) ) ;
2017-11-27 04:21:54 +01:00
return true ;
}
2015-07-22 06:00:47 +02:00
bool lcPiecesLibrary : : LoadCacheIndex ( const QString & FileName )
2013-08-09 06:57:18 +02:00
{
2015-07-22 06:00:47 +02:00
lcMemFile IndexFile ;
2013-08-09 06:57:18 +02:00
2017-11-27 04:21:54 +01:00
if ( ! ReadArchiveCacheFile ( FileName , IndexFile ) )
2015-07-22 06:00:47 +02:00
return false ;
2017-07-27 21:40:52 +02:00
quint32 NumFiles ;
2015-07-22 06:00:47 +02:00
2017-07-24 04:35:18 +02:00
if ( IndexFile . ReadBuffer ( ( char * ) & NumFiles , sizeof ( NumFiles ) ) = = 0 | | NumFiles ! = mPieces . size ( ) )
2015-07-22 06:00:47 +02:00
return false ;
2013-08-09 06:57:18 +02:00
2018-02-22 02:27:24 +01:00
for ( const auto & PieceIt : mPieces )
2013-08-09 06:57:18 +02:00
{
2017-07-24 04:35:18 +02:00
PieceInfo * Info = PieceIt . second ;
2015-07-22 06:00:47 +02:00
quint8 Length ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
if ( IndexFile . ReadBuffer ( ( char * ) & Length , sizeof ( Length ) ) = = 0 | | Length > = sizeof ( Info - > m_strDescription ) )
return false ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
if ( IndexFile . ReadBuffer ( ( char * ) Info - > m_strDescription , Length ) = = 0 | | IndexFile . ReadBuffer ( ( char * ) & Info - > mFlags , sizeof ( Info - > mFlags ) ) = = 0 )
return false ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
Info - > m_strDescription [ Length ] = 0 ;
}
2014-05-08 00:58:59 +02:00
2015-07-22 06:00:47 +02:00
return true ;
}
2014-05-08 00:58:59 +02:00
2017-11-27 04:21:54 +01:00
bool lcPiecesLibrary : : SaveArchiveCacheIndex ( const QString & FileName )
2015-07-22 06:00:47 +02:00
{
lcMemFile IndexFile ;
2013-08-09 06:57:18 +02:00
2019-05-18 20:33:27 +02:00
quint32 NumFiles = ( quint32 ) mPieces . size ( ) ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
if ( IndexFile . WriteBuffer ( ( char * ) & NumFiles , sizeof ( NumFiles ) ) = = 0 )
return false ;
2018-02-22 02:27:24 +01:00
for ( const auto & PieceIt : mPieces )
2013-08-09 06:57:18 +02:00
{
2017-07-24 04:35:18 +02:00
PieceInfo * Info = PieceIt . second ;
2016-02-19 18:53:54 +01:00
quint8 Length = ( quint8 ) strlen ( Info - > m_strDescription ) ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
if ( IndexFile . WriteBuffer ( ( char * ) & Length , sizeof ( Length ) ) = = 0 )
return false ;
if ( IndexFile . WriteBuffer ( ( char * ) Info - > m_strDescription , Length ) = = 0 | | IndexFile . WriteBuffer ( ( char * ) & Info - > mFlags , sizeof ( Info - > mFlags ) ) = = 0 )
return false ;
2013-08-09 06:57:18 +02:00
}
2017-11-27 04:21:54 +01:00
return WriteArchiveCacheFile ( FileName , IndexFile ) ;
2015-07-22 06:00:47 +02:00
}
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
bool lcPiecesLibrary : : LoadCachePiece ( PieceInfo * Info )
{
2017-07-27 18:21:55 +02:00
QString FileName = QFileInfo ( QDir ( mCachePath ) , QString : : fromLatin1 ( Info - > mFileName ) ) . absoluteFilePath ( ) ;
2015-07-22 06:00:47 +02:00
lcMemFile MeshData ;
2013-08-09 06:57:18 +02:00
2017-11-27 04:21:54 +01:00
if ( ! ReadArchiveCacheFile ( FileName , MeshData ) )
2015-07-22 06:00:47 +02:00
return false ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
quint32 Flags ;
if ( MeshData . ReadBuffer ( ( char * ) & Flags , sizeof ( Flags ) ) = = 0 )
return false ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
Info - > mFlags = Flags ;
2013-08-09 06:57:18 +02:00
2017-01-23 04:28:05 +01:00
lcMesh * Mesh = new lcMesh ;
if ( Mesh - > FileLoad ( MeshData ) )
{
Info - > SetMesh ( Mesh ) ;
return true ;
}
else
{
delete Mesh ;
return false ;
}
2015-07-22 06:00:47 +02:00
}
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
bool lcPiecesLibrary : : SaveCachePiece ( PieceInfo * Info )
{
lcMemFile MeshData ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
quint32 Flags = Info - > mFlags ;
if ( MeshData . WriteBuffer ( ( char * ) & Flags , sizeof ( Flags ) ) = = 0 )
return false ;
2013-08-09 06:57:18 +02:00
2015-07-22 06:00:47 +02:00
if ( ! Info - > GetMesh ( ) - > FileSave ( MeshData ) )
return false ;
2013-08-09 06:57:18 +02:00
2017-07-27 18:21:55 +02:00
QString FileName = QFileInfo ( QDir ( mCachePath ) , QString : : fromLatin1 ( Info - > mFileName ) ) . absoluteFilePath ( ) ;
2013-08-09 06:57:18 +02:00
2017-11-27 04:21:54 +01:00
return WriteArchiveCacheFile ( FileName , MeshData ) ;
2013-08-09 06:57:18 +02:00
}
2017-01-23 07:44:54 +01:00
class lcSleeper : public QThread
{
public :
static void msleep ( unsigned long Msecs )
{
QThread : : msleep ( Msecs ) ;
}
} ;
2017-01-23 04:28:05 +01:00
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 )
2017-01-23 07:44:54 +01:00
lcSleeper : : msleep ( 10 ) ;
2017-01-23 04:28:05 +01:00
}
}
}
else
{
if ( Info - > AddRef ( ) = = 1 )
{
if ( Priority )
mLoadQueue . prepend ( Info ) ;
else
mLoadQueue . append ( Info ) ;
2017-12-22 13:38:47 +01:00
mLoadFutures . append ( QtConcurrent : : run ( [ this ] ( ) { LoadQueuedPiece ( ) ; } ) ) ;
2017-01-23 04:28:05 +01:00
}
}
}
void lcPiecesLibrary : : ReleasePieceInfo ( PieceInfo * Info )
{
QMutexLocker LoadLock ( & mLoadMutex ) ;
if ( Info - > GetRefCount ( ) = = 0 | | Info - > Release ( ) = = 0 )
Info - > Unload ( ) ;
}
void lcPiecesLibrary : : LoadQueuedPiece ( )
{
mLoadMutex . lock ( ) ;
2017-04-14 02:26:40 +02:00
PieceInfo * Info = nullptr ;
2017-01-23 04:28:05 +01:00
while ( ! mLoadQueue . isEmpty ( ) )
{
Info = mLoadQueue . takeFirst ( ) ;
if ( Info - > mState = = LC_PIECEINFO_UNLOADED & & Info - > GetRefCount ( ) > 0 )
{
Info - > mState = LC_PIECEINFO_LOADING ;
break ;
}
2017-01-24 05:26:57 +01:00
2017-04-14 02:26:40 +02:00
Info = nullptr ;
2017-01-23 04:28:05 +01:00
}
mLoadMutex . unlock ( ) ;
if ( Info )
Info - > Load ( ) ;
emit PartLoaded ( Info ) ;
}
void lcPiecesLibrary : : WaitForLoadQueue ( )
{
for ( QFuture < void > & Future : mLoadFutures )
Future . waitForFinished ( ) ;
mLoadFutures . clear ( ) ;
}
2015-05-24 06:36:25 +02:00
struct lcMergeSection
2013-08-09 06:57:18 +02:00
{
2015-05-24 06:36:25 +02:00
lcLibraryMeshSection * Shared ;
lcLibraryMeshSection * Lod ;
} ;
static int LibraryMeshSectionCompare ( lcMergeSection const & First , lcMergeSection const & Second )
{
lcLibraryMeshSection * a = First . Lod ? First . Lod : First . Shared ;
lcLibraryMeshSection * b = Second . Lod ? Second . Lod : Second . Shared ;
2013-08-09 06:57:18 +02:00
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 ,
2016-08-22 03:11:32 +02:00
LC_MESH_CONDITIONAL_LINES
2013-08-09 06:57:18 +02:00
} ;
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 ;
}
2017-01-23 04:28:05 +01:00
bool lcPiecesLibrary : : LoadPieceData ( PieceInfo * Info )
2013-08-09 06:57:18 +02:00
{
lcLibraryMeshData MeshData ;
2013-08-16 01:43:18 +02:00
lcArray < lcLibraryTextureMap > TextureStack ;
2013-08-09 06:57:18 +02:00
2016-05-28 19:35:13 +02:00
bool Loaded = false ;
bool SaveCache = false ;
2014-05-18 01:03:05 +02:00
if ( Info - > mZipFileType ! = LC_NUM_ZIPFILES & & mZipFiles [ Info - > mZipFileType ] )
2013-08-09 06:57:18 +02:00
{
if ( LoadCachePiece ( Info ) )
return true ;
lcMemFile PieceFile ;
2016-05-28 19:35:13 +02:00
if ( mZipFiles [ Info - > mZipFileType ] - > ExtractFile ( Info - > mZipFileIndex , PieceFile ) )
2017-07-02 02:12:09 +02:00
Loaded = ReadMeshData ( PieceFile , lcMatrix44Identity ( ) , 16 , false , TextureStack , MeshData , LC_MESHDATA_SHARED , true , nullptr , false ) ;
2013-08-09 06:57:18 +02:00
2016-05-28 19:35:13 +02:00
SaveCache = Loaded & & ( Info - > mZipFileType = = LC_ZIPFILE_OFFICIAL ) ;
2013-08-09 06:57:18 +02:00
}
else
{
char FileName [ LC_MAXPATH ] ;
lcDiskFile PieceFile ;
2017-03-19 21:12:24 +01:00
if ( mHasUnofficial )
{
2017-07-27 18:21:55 +02:00
sprintf ( FileName , " unofficial/parts/%s " , Info - > mFileName ) ;
2017-05-29 22:31:24 +02:00
PieceFile . SetFileName ( mLibraryDir . absoluteFilePath ( QLatin1String ( FileName ) ) ) ;
if ( PieceFile . Open ( QIODevice : : ReadOnly ) )
2017-07-02 02:12:09 +02:00
Loaded = ReadMeshData ( PieceFile , lcMatrix44Identity ( ) , 16 , false , TextureStack , MeshData , LC_MESHDATA_SHARED , true , nullptr , false ) ;
2017-03-19 21:12:24 +01:00
}
if ( ! Loaded )
{
2017-07-27 18:21:55 +02:00
sprintf ( FileName , " parts/%s " , Info - > mFileName ) ;
2017-05-29 22:31:24 +02:00
PieceFile . SetFileName ( mLibraryDir . absoluteFilePath ( QLatin1String ( FileName ) ) ) ;
if ( PieceFile . Open ( QIODevice : : ReadOnly ) )
2017-07-02 02:12:09 +02:00
Loaded = ReadMeshData ( PieceFile , lcMatrix44Identity ( ) , 16 , false , TextureStack , MeshData , LC_MESHDATA_SHARED , true , nullptr , false ) ;
2017-03-19 21:12:24 +01:00
}
2016-05-28 19:35:13 +02:00
}
2016-11-26 02:12:19 +01:00
2017-11-25 21:57:41 +01:00
if ( ! Loaded | | mCancelLoading )
2016-05-28 19:35:13 +02:00
return false ;
2017-01-23 04:28:05 +01:00
CreateMesh ( Info , MeshData ) ;
2015-02-23 01:50:37 +01:00
2016-05-28 19:35:13 +02:00
if ( SaveCache )
2015-07-22 06:00:47 +02:00
SaveCachePiece ( Info ) ;
2015-02-23 01:50:37 +01:00
return true ;
}
2016-02-29 21:13:54 +01:00
lcMesh * lcPiecesLibrary : : CreateMesh ( PieceInfo * Info , lcLibraryMeshData & MeshData )
2015-02-23 01:50:37 +01:00
{
2013-08-09 06:57:18 +02:00
lcMesh * Mesh = new lcMesh ( ) ;
2015-05-24 06:36:25 +02:00
int BaseVertices [ LC_NUM_MESHDATA_TYPES ] ;
int BaseTexturedVertices [ LC_NUM_MESHDATA_TYPES ] ;
int NumVertices = 0 ;
int NumTexturedVertices = 0 ;
2019-05-28 01:07:20 +02:00
std : : vector < quint32 > IndexRemap [ LC_NUM_MESHDATA_TYPES ] ;
std : : vector < quint32 > TexturedIndexRemap [ LC_NUM_MESHDATA_TYPES ] ;
2013-08-09 06:57:18 +02:00
2019-05-28 01:07:20 +02:00
if ( ! MeshData . mHasTextures )
2013-08-09 06:57:18 +02:00
{
2019-05-28 01:07:20 +02:00
for ( int MeshDataIdx = 0 ; MeshDataIdx < LC_NUM_MESHDATA_TYPES ; MeshDataIdx + + )
2015-05-24 06:36:25 +02:00
{
2019-05-28 01:07:20 +02:00
lcArray < lcLibraryMeshSection * > & Sections = MeshData . mSections [ MeshDataIdx ] ;
for ( int SectionIdx = 0 ; SectionIdx < Sections . GetSize ( ) ; SectionIdx + + )
{
lcLibraryMeshSection * Section = Sections [ SectionIdx ] ;
Section - > mColor = lcGetColorIndex ( Section - > mColor ) ;
}
BaseVertices [ MeshDataIdx ] = NumVertices ;
NumVertices + = MeshData . mVertices [ MeshDataIdx ] . GetSize ( ) ;
2015-05-24 06:36:25 +02:00
}
2019-05-28 01:07:20 +02:00
}
else
{
for ( int MeshDataIdx = 0 ; MeshDataIdx < LC_NUM_MESHDATA_TYPES ; MeshDataIdx + + )
{
lcArray < lcLibraryMeshSection * > & Sections = MeshData . mSections [ MeshDataIdx ] ;
2013-08-09 06:57:18 +02:00
2019-05-28 01:07:20 +02:00
for ( int SectionIdx = 0 ; SectionIdx < Sections . GetSize ( ) ; SectionIdx + + )
{
lcLibraryMeshSection * Section = Sections [ SectionIdx ] ;
Section - > mColor = lcGetColorIndex ( Section - > mColor ) ;
}
BaseVertices [ MeshDataIdx ] = NumVertices ;
BaseTexturedVertices [ MeshDataIdx ] = NumTexturedVertices ;
const lcArray < lcLibraryMeshVertex > & Vertices = MeshData . mVertices [ MeshDataIdx ] ;
IndexRemap [ MeshDataIdx ] . resize ( Vertices . GetSize ( ) ) ;
TexturedIndexRemap [ MeshDataIdx ] . resize ( Vertices . GetSize ( ) ) ;
for ( int VertexIdx = 0 ; VertexIdx < Vertices . GetSize ( ) ; VertexIdx + + )
{
const lcLibraryMeshVertex & Vertex = Vertices [ VertexIdx ] ;
if ( Vertex . Usage & LC_LIBRARY_VERTEX_UNTEXTURED )
{
IndexRemap [ MeshDataIdx ] [ VertexIdx ] = NumVertices ;
NumVertices + + ;
}
if ( Vertex . Usage & LC_LIBRARY_VERTEX_TEXTURED )
{
TexturedIndexRemap [ MeshDataIdx ] [ VertexIdx ] = NumTexturedVertices ;
NumTexturedVertices + + ;
}
}
}
2013-08-09 06:57:18 +02:00
}
2017-12-02 21:22:04 +01:00
quint16 NumSections [ LC_NUM_MESH_LODS ] ;
2015-05-24 06:36:25 +02:00
int NumIndices = 0 ;
lcArray < lcMergeSection > MergeSections [ LC_NUM_MESH_LODS ] ;
for ( int LodIdx = 0 ; LodIdx < LC_NUM_MESH_LODS ; LodIdx + + )
{
const lcArray < lcLibraryMeshSection * > & SharedSections = MeshData . mSections [ LC_MESHDATA_SHARED ] ;
const lcArray < lcLibraryMeshSection * > & Sections = MeshData . mSections [ LodIdx ] ;
for ( int SharedSectionIdx = 0 ; SharedSectionIdx < SharedSections . GetSize ( ) ; SharedSectionIdx + + )
{
lcLibraryMeshSection * SharedSection = SharedSections [ SharedSectionIdx ] ;
NumIndices + = SharedSection - > mIndices . GetSize ( ) ;
lcMergeSection & MergeSection = MergeSections [ LodIdx ] . Add ( ) ;
MergeSection . Shared = SharedSection ;
2017-04-14 02:26:40 +02:00
MergeSection . Lod = nullptr ;
2015-05-24 06:36:25 +02:00
}
for ( int SectionIdx = 0 ; SectionIdx < Sections . GetSize ( ) ; SectionIdx + + )
{
lcLibraryMeshSection * Section = Sections [ SectionIdx ] ;
bool Found = false ;
NumIndices + = Section - > mIndices . GetSize ( ) ;
for ( int SharedSectionIdx = 0 ; SharedSectionIdx < SharedSections . GetSize ( ) ; SharedSectionIdx + + )
{
lcLibraryMeshSection * SharedSection = SharedSections [ SharedSectionIdx ] ;
if ( SharedSection - > mColor = = Section - > mColor & & SharedSection - > mPrimitiveType = = Section - > mPrimitiveType & & SharedSection - > mTexture = = Section - > mTexture )
{
lcMergeSection & MergeSection = MergeSections [ LodIdx ] [ SharedSectionIdx ] ;
MergeSection . Lod = Section ;
Found = true ;
break ;
}
}
if ( ! Found )
{
lcMergeSection & MergeSection = MergeSections [ LodIdx ] . Add ( ) ;
2017-04-14 02:26:40 +02:00
MergeSection . Shared = nullptr ;
2015-05-24 06:36:25 +02:00
MergeSection . Lod = Section ;
}
}
NumSections [ LodIdx ] = MergeSections [ LodIdx ] . GetSize ( ) ;
MergeSections [ LodIdx ] . Sort ( LibraryMeshSectionCompare ) ;
}
2013-08-09 06:57:18 +02:00
2015-05-24 06:36:25 +02:00
Mesh - > Create ( NumSections , NumVertices , NumTexturedVertices , NumIndices ) ;
2013-08-09 06:57:18 +02:00
2015-04-26 20:14:33 +02:00
lcVertex * DstVerts = ( lcVertex * ) Mesh - > mVertexData ;
2013-08-09 06:57:18 +02:00
lcVector3 Min ( FLT_MAX , FLT_MAX , FLT_MAX ) , Max ( - FLT_MAX , - FLT_MAX , - FLT_MAX ) ;
2019-02-23 02:02:38 +01:00
bool UpdatedBoundingBox = false ;
2013-08-09 06:57:18 +02:00
2019-05-28 01:07:20 +02:00
if ( ! MeshData . mHasTextures )
2013-08-09 06:57:18 +02:00
{
2019-05-28 01:07:20 +02:00
for ( int MeshDataIdx = 0 ; MeshDataIdx < LC_NUM_MESHDATA_TYPES ; MeshDataIdx + + )
{
const lcArray < lcLibraryMeshVertex > & Vertices = MeshData . mVertices [ MeshDataIdx ] ;
for ( const lcLibraryMeshVertex & SrcVertex : Vertices )
{
lcVertex & DstVertex = * DstVerts + + ;
DstVertex . Position = lcVector3LDrawToLeoCAD ( SrcVertex . Position ) ;
DstVertex . Normal = lcPackNormal ( lcVector3LDrawToLeoCAD ( SrcVertex . Normal ) ) ;
}
2013-08-09 06:57:18 +02:00
2019-05-28 01:07:20 +02:00
for ( const lcLibraryMeshSection * Section : MeshData . mSections [ MeshDataIdx ] )
{
if ( Section - > mPrimitiveType ! = LC_MESH_TRIANGLES )
continue ;
UpdatedBoundingBox = true ;
for ( quint32 Index : Section - > mIndices )
{
lcVector3 Position = lcVector3LDrawToLeoCAD ( Vertices [ Index ] . Position ) ;
Min = lcMin ( Min , Position ) ;
Max = lcMax ( Max , Position ) ;
}
}
}
}
else
{
for ( int MeshDataIdx = 0 ; MeshDataIdx < LC_NUM_MESHDATA_TYPES ; MeshDataIdx + + )
2015-05-24 06:36:25 +02:00
{
2019-05-28 01:07:20 +02:00
for ( const lcLibraryMeshVertex & SrcVertex : MeshData . mVertices [ MeshDataIdx ] )
{
if ( ( SrcVertex . Usage & LC_LIBRARY_VERTEX_UNTEXTURED ) = = 0 )
continue ;
2019-06-02 18:39:12 +02:00
lcVertex & DstVertex = * DstVerts + + ;
2019-05-28 01:07:20 +02:00
DstVertex . Position = lcVector3LDrawToLeoCAD ( SrcVertex . Position ) ;
DstVertex . Normal = lcPackNormal ( lcVector3LDrawToLeoCAD ( SrcVertex . Normal ) ) ;
}
2018-01-21 02:35:21 +01:00
}
2019-05-28 01:07:20 +02:00
lcVertexTextured * DstTexturedVerts = ( lcVertexTextured * ) DstVerts ;
for ( int MeshDataIdx = 0 ; MeshDataIdx < LC_NUM_MESHDATA_TYPES ; MeshDataIdx + + )
2018-01-21 02:35:21 +01:00
{
2019-05-28 01:07:20 +02:00
for ( const lcLibraryMeshVertex & SrcVertex : MeshData . mVertices [ MeshDataIdx ] )
{
if ( ( SrcVertex . Usage & LC_LIBRARY_VERTEX_TEXTURED ) = = 0 )
continue ;
2013-08-09 06:57:18 +02:00
2019-05-28 01:07:20 +02:00
lcVertexTextured & DstVertex = * DstTexturedVerts + + ;
2019-02-23 02:02:38 +01:00
2019-05-28 01:07:20 +02:00
DstVertex . Position = lcVector3LDrawToLeoCAD ( SrcVertex . Position ) ;
DstVertex . Normal = lcPackNormal ( lcVector3LDrawToLeoCAD ( SrcVertex . Normal ) ) ;
DstVertex . TexCoord = SrcVertex . TexCoord ;
lcVector3 & Position = DstVertex . Position ;
2018-01-21 02:35:21 +01:00
Min = lcMin ( Min , Position ) ;
Max = lcMax ( Max , Position ) ;
}
2015-05-24 06:36:25 +02:00
}
2013-08-09 06:57:18 +02:00
2019-05-28 01:07:20 +02:00
for ( int MeshDataIdx = 0 ; MeshDataIdx < LC_NUM_MESHDATA_TYPES ; MeshDataIdx + + )
2015-05-24 06:36:25 +02:00
{
2019-05-28 01:07:20 +02:00
const lcArray < lcLibraryMeshVertex > & Vertices = MeshData . mVertices [ MeshDataIdx ] ;
2013-08-09 06:57:18 +02:00
2019-05-28 01:07:20 +02:00
for ( lcLibraryMeshSection * Section : MeshData . mSections [ MeshDataIdx ] )
{
if ( Section - > mPrimitiveType = = LC_MESH_TRIANGLES )
{
UpdatedBoundingBox = true ;
for ( quint32 & Index : Section - > mIndices )
{
lcVector3 Position = lcVector3LDrawToLeoCAD ( Vertices [ Index ] . Position ) ;
Min = lcMin ( Min , Position ) ;
Max = lcMax ( Max , Position ) ;
2013-08-09 06:57:18 +02:00
2019-05-28 01:07:20 +02:00
Index = IndexRemap [ MeshDataIdx ] [ Index ] ;
}
}
else
{
if ( ! Section - > mTexture )
{
for ( quint32 & Index : Section - > mIndices )
Index = IndexRemap [ MeshDataIdx ] [ Index ] ;
}
else
{
for ( quint32 & Index : Section - > mIndices )
Index = TexturedIndexRemap [ MeshDataIdx ] [ Index ] ;
}
}
}
2015-05-24 06:36:25 +02:00
}
2013-08-09 06:57:18 +02:00
}
2019-05-28 01:07:20 +02:00
if ( ! UpdatedBoundingBox )
Min = Max = lcVector3 ( 0.0f , 0.0f , 0.0f ) ;
2016-02-19 18:53:54 +01:00
Mesh - > mBoundingBox . Max = Max ;
Mesh - > mBoundingBox . Min = Min ;
2015-05-24 06:36:25 +02:00
Mesh - > mRadius = lcLength ( ( Max - Min ) / 2.0f ) ;
2013-08-09 06:57:18 +02:00
NumIndices = 0 ;
2015-05-24 06:36:25 +02:00
for ( int LodIdx = 0 ; LodIdx < LC_NUM_MESH_LODS ; LodIdx + + )
{
for ( int SectionIdx = 0 ; SectionIdx < MergeSections [ LodIdx ] . GetSize ( ) ; SectionIdx + + )
{
lcMergeSection & MergeSection = MergeSections [ LodIdx ] [ SectionIdx ] ;
lcMeshSection & DstSection = Mesh - > mLods [ LodIdx ] . Sections [ SectionIdx ] ;
lcLibraryMeshSection * SetupSection = MergeSection . Shared ? MergeSection . Shared : MergeSection . Lod ;
DstSection . ColorIndex = SetupSection - > mColor ;
2016-08-22 03:11:32 +02:00
DstSection . PrimitiveType = SetupSection - > mPrimitiveType ;
2015-05-24 06:36:25 +02:00
DstSection . NumIndices = 0 ;
DstSection . Texture = SetupSection - > mTexture ;
if ( DstSection . Texture )
DstSection . Texture - > AddRef ( ) ;
if ( Mesh - > mNumVertices < 0x10000 )
{
DstSection . IndexOffset = NumIndices * 2 ;
2017-12-02 21:22:04 +01:00
quint16 * Index = ( quint16 * ) Mesh - > mIndexData + NumIndices ;
2015-05-24 06:36:25 +02:00
if ( MergeSection . Shared )
{
2017-12-02 21:22:04 +01:00
quint16 BaseVertex = DstSection . Texture ? BaseTexturedVertices [ LC_MESHDATA_SHARED ] : BaseVertices [ LC_MESHDATA_SHARED ] ;
2015-05-24 06:36:25 +02:00
lcLibraryMeshSection * SrcSection = MergeSection . Shared ;
for ( int IndexIdx = 0 ; IndexIdx < SrcSection - > mIndices . GetSize ( ) ; IndexIdx + + )
* Index + + = BaseVertex + SrcSection - > mIndices [ IndexIdx ] ;
DstSection . NumIndices + = SrcSection - > mIndices . GetSize ( ) ;
}
if ( MergeSection . Lod )
{
2017-12-02 21:22:04 +01:00
quint16 BaseVertex = DstSection . Texture ? BaseTexturedVertices [ LodIdx ] : BaseVertices [ LodIdx ] ;
2015-05-24 06:36:25 +02:00
lcLibraryMeshSection * SrcSection = MergeSection . Lod ;
for ( int IndexIdx = 0 ; IndexIdx < SrcSection - > mIndices . GetSize ( ) ; IndexIdx + + )
* Index + + = BaseVertex + SrcSection - > mIndices [ IndexIdx ] ;
DstSection . NumIndices + = SrcSection - > mIndices . GetSize ( ) ;
}
}
else
{
DstSection . IndexOffset = NumIndices * 4 ;
2017-12-02 21:22:04 +01:00
quint32 * Index = ( quint32 * ) Mesh - > mIndexData + NumIndices ;
2015-05-24 06:36:25 +02:00
if ( MergeSection . Shared )
{
2017-12-02 21:22:04 +01:00
quint32 BaseVertex = DstSection . Texture ? BaseTexturedVertices [ LC_MESHDATA_SHARED ] : BaseVertices [ LC_MESHDATA_SHARED ] ;
2015-05-24 06:36:25 +02:00
lcLibraryMeshSection * SrcSection = MergeSection . Shared ;
for ( int IndexIdx = 0 ; IndexIdx < SrcSection - > mIndices . GetSize ( ) ; IndexIdx + + )
* Index + + = BaseVertex + SrcSection - > mIndices [ IndexIdx ] ;
DstSection . NumIndices + = SrcSection - > mIndices . GetSize ( ) ;
}
if ( MergeSection . Lod )
{
2017-12-02 21:22:04 +01:00
quint32 BaseVertex = DstSection . Texture ? BaseTexturedVertices [ LodIdx ] : BaseVertices [ LodIdx ] ;
2016-05-28 20:18:00 +02:00
lcLibraryMeshSection * SrcSection = MergeSection . Lod ;
2015-05-24 06:36:25 +02:00
for ( int IndexIdx = 0 ; IndexIdx < SrcSection - > mIndices . GetSize ( ) ; IndexIdx + + )
* Index + + = BaseVertex + SrcSection - > mIndices [ IndexIdx ] ;
DstSection . NumIndices + = SrcSection - > mIndices . GetSize ( ) ;
}
}
2016-02-29 21:13:54 +01:00
if ( Info )
2015-05-24 06:36:25 +02:00
{
2016-08-22 03:11:32 +02:00
if ( DstSection . PrimitiveType = = LC_MESH_TRIANGLES | | DstSection . PrimitiveType = = LC_MESH_TEXTURED_TRIANGLES )
2015-05-24 06:36:25 +02:00
{
2016-02-29 21:13:54 +01:00
if ( DstSection . ColorIndex = = gDefaultColor )
Info - > mFlags | = LC_PIECE_HAS_DEFAULT ;
2015-05-24 06:36:25 +02:00
else
2016-02-29 21:13:54 +01:00
{
if ( lcIsColorTranslucent ( DstSection . ColorIndex ) )
Info - > mFlags | = LC_PIECE_HAS_TRANSLUCENT ;
else
Info - > mFlags | = LC_PIECE_HAS_SOLID ;
}
2015-05-24 06:36:25 +02:00
}
2016-02-29 21:13:54 +01:00
else
Info - > mFlags | = LC_PIECE_HAS_LINES ;
2017-03-23 07:35:02 +01:00
if ( DstSection . PrimitiveType = = LC_MESH_TEXTURED_TRIANGLES | | DstSection . PrimitiveType = = LC_MESH_TEXTURED_LINES )
Info - > mFlags | = LC_PIECE_HAS_TEXTURE ;
2015-05-24 06:36:25 +02:00
}
NumIndices + = DstSection . NumIndices ;
}
}
/*
2013-08-09 06:57:18 +02:00
for ( int SectionIdx = 0 ; SectionIdx < MeshData . mSections . GetSize ( ) ; SectionIdx + + )
{
lcMeshSection & DstSection = Mesh - > mSections [ SectionIdx ] ;
lcLibraryMeshSection * SrcSection = MeshData . mSections [ SectionIdx ] ;
DstSection . ColorIndex = SrcSection - > mColor ;
2016-08-22 03:11:32 +02:00
DstSection . PrimitiveType = SrcSection - > mPrimitiveType ;
2013-08-09 06:57:18 +02:00
DstSection . NumIndices = SrcSection - > mIndices . GetSize ( ) ;
DstSection . Texture = SrcSection - > mTexture ;
if ( DstSection . Texture )
DstSection . Texture - > AddRef ( ) ;
if ( Mesh - > mNumVertices < 0x10000 )
{
DstSection . IndexOffset = NumIndices * 2 ;
2017-12-02 21:22:04 +01:00
quint16 * Index = ( quint16 * ) Mesh - > mIndexData + NumIndices ;
2013-08-09 06:57:18 +02:00
for ( int IndexIdx = 0 ; IndexIdx < DstSection . NumIndices ; IndexIdx + + )
* Index + + = SrcSection - > mIndices [ IndexIdx ] ;
}
else
{
DstSection . IndexOffset = NumIndices * 4 ;
2017-12-02 21:22:04 +01:00
quint32 * Index = ( quint32 * ) Mesh - > mIndexData + NumIndices ;
2013-08-09 06:57:18 +02:00
for ( int IndexIdx = 0 ; IndexIdx < DstSection . NumIndices ; IndexIdx + + )
* Index + + = SrcSection - > mIndices [ IndexIdx ] ;
}
2016-08-22 03:11:32 +02:00
if ( DstSection . PrimitiveType = = LC_MESH_TRIANGLES | | DstSection . PrimitiveType = = LC_MESH_TEXTURED_TRIANGLES )
2013-08-09 06:57:18 +02:00
{
if ( DstSection . ColorIndex = = gDefaultColor )
Info - > mFlags | = LC_PIECE_HAS_DEFAULT ;
else
{
if ( lcIsColorTranslucent ( DstSection . ColorIndex ) )
Info - > mFlags | = LC_PIECE_HAS_TRANSLUCENT ;
else
Info - > mFlags | = LC_PIECE_HAS_SOLID ;
}
}
else
Info - > mFlags | = LC_PIECE_HAS_LINES ;
NumIndices + = DstSection . NumIndices ;
}
2015-05-24 06:36:25 +02:00
*/
2016-02-29 21:13:54 +01:00
if ( Info )
Info - > SetMesh ( Mesh ) ;
return Mesh ;
2013-08-09 06:57:18 +02:00
}
2016-12-28 22:30:31 +01:00
void lcPiecesLibrary : : ReleaseBuffers ( lcContext * Context )
{
Context - > DestroyVertexBuffer ( mVertexBuffer ) ;
Context - > DestroyIndexBuffer ( mIndexBuffer ) ;
mBuffersDirty = true ;
}
2015-04-26 20:14:33 +02:00
void lcPiecesLibrary : : UpdateBuffers ( lcContext * Context )
{
2015-05-09 21:54:29 +02:00
if ( ! gSupportsVertexBufferObject | | ! mBuffersDirty )
2015-04-26 20:14:33 +02:00
return ;
int VertexDataSize = 0 ;
int IndexDataSize = 0 ;
2018-02-22 02:27:24 +01:00
for ( const auto & PieceIt : mPieces )
2015-04-26 20:14:33 +02:00
{
2017-07-24 04:35:18 +02:00
PieceInfo * Info = PieceIt . second ;
2015-04-26 20:41:16 +02:00
lcMesh * Mesh = Info - > IsPlaceholder ( ) ? gPlaceholderMesh : Info - > GetMesh ( ) ;
2015-04-26 20:14:33 +02:00
if ( ! Mesh )
continue ;
2016-05-29 04:46:34 +02:00
if ( Mesh - > mVertexDataSize > 16 * 1024 * 1024 | | Mesh - > mIndexDataSize > 16 * 1024 * 1024 )
continue ;
2015-04-26 20:14:33 +02:00
VertexDataSize + = Mesh - > mVertexDataSize ;
IndexDataSize + = Mesh - > mIndexDataSize ;
}
Context - > DestroyVertexBuffer ( mVertexBuffer ) ;
Context - > DestroyIndexBuffer ( mIndexBuffer ) ;
if ( ! VertexDataSize | | ! IndexDataSize )
return ;
void * VertexData = malloc ( VertexDataSize ) ;
void * IndexData = malloc ( IndexDataSize ) ;
VertexDataSize = 0 ;
IndexDataSize = 0 ;
2018-02-22 02:27:24 +01:00
for ( const auto & PieceIt : mPieces )
2015-04-26 20:14:33 +02:00
{
2017-07-24 04:35:18 +02:00
PieceInfo * Info = PieceIt . second ;
2015-04-26 20:41:16 +02:00
lcMesh * Mesh = Info - > IsPlaceholder ( ) ? gPlaceholderMesh : Info - > GetMesh ( ) ;
2015-04-26 20:14:33 +02:00
if ( ! Mesh )
continue ;
2016-05-29 04:46:34 +02:00
if ( Mesh - > mVertexDataSize > 16 * 1024 * 1024 | | Mesh - > mIndexDataSize > 16 * 1024 * 1024 )
continue ;
2015-04-26 20:14:33 +02:00
Mesh - > mVertexCacheOffset = VertexDataSize ;
Mesh - > mIndexCacheOffset = IndexDataSize ;
memcpy ( ( char * ) VertexData + VertexDataSize , Mesh - > mVertexData , Mesh - > mVertexDataSize ) ;
memcpy ( ( char * ) IndexData + IndexDataSize , Mesh - > mIndexData , Mesh - > mIndexDataSize ) ;
VertexDataSize + = Mesh - > mVertexDataSize ;
IndexDataSize + = Mesh - > mIndexDataSize ;
}
mVertexBuffer = Context - > CreateVertexBuffer ( VertexDataSize , VertexData ) ;
mIndexBuffer = Context - > CreateIndexBuffer ( IndexDataSize , IndexData ) ;
mBuffersDirty = false ;
free ( VertexData ) ;
free ( IndexData ) ;
}
2015-11-16 03:41:16 +01:00
void lcPiecesLibrary : : UnloadUnusedParts ( )
{
2017-01-23 04:28:05 +01:00
QMutexLocker LoadLock ( & mLoadMutex ) ;
2018-02-22 02:27:24 +01:00
for ( const auto & PieceIt : mPieces )
2017-01-23 04:28:05 +01:00
{
2017-07-24 04:35:18 +02:00
PieceInfo * Info = PieceIt . second ;
2017-01-23 04:28:05 +01:00
if ( Info - > GetRefCount ( ) = = 0 & & Info - > mState ! = LC_PIECEINFO_UNLOADED )
ReleasePieceInfo ( Info ) ;
}
2015-11-16 03:41:16 +01:00
}
2013-08-09 06:57:18 +02:00
bool lcPiecesLibrary : : LoadTexture ( lcTexture * Texture )
{
2019-06-03 22:23:04 +02:00
char FileName [ 2 * LC_MAXPATH ] ;
2013-08-09 06:57:18 +02:00
2014-05-08 00:58:59 +02:00
if ( mZipFiles [ LC_ZIPFILE_OFFICIAL ] )
2013-08-09 06:57:18 +02:00
{
lcMemFile TextureFile ;
2018-02-17 20:32:29 +01:00
sprintf ( FileName , " parts/textures/%s.png " , Texture - > mName ) ;
2013-08-09 06:57:18 +02:00
2014-05-08 00:58:59 +02:00
if ( ! mZipFiles [ LC_ZIPFILE_UNOFFICIAL ] | | ! mZipFiles [ LC_ZIPFILE_UNOFFICIAL ] - > ExtractFile ( FileName , TextureFile ) )
2017-12-22 13:38:47 +01:00
{
2018-02-17 20:32:29 +01:00
sprintf ( FileName , " ldraw/parts/textures/%s.png " , Texture - > mName ) ;
2017-12-22 13:38:47 +01:00
2014-05-08 00:58:59 +02:00
if ( ! mZipFiles [ LC_ZIPFILE_OFFICIAL ] - > ExtractFile ( FileName , TextureFile ) )
return false ;
2017-12-22 13:38:47 +01:00
}
2013-08-09 06:57:18 +02:00
2018-02-17 20:32:29 +01:00
return Texture - > Load ( TextureFile ) ;
2013-08-09 06:57:18 +02:00
}
else
{
2018-02-17 20:32:29 +01:00
sprintf ( FileName , " parts/textures/%s.png " , Texture - > mName ) ;
if ( Texture - > Load ( mLibraryDir . absoluteFilePath ( QLatin1String ( FileName ) ) ) )
return true ;
# if defined(Q_OS_MACOS) || defined(Q_OS_LINUX)
char Name [ LC_MAXPATH ] ;
strcpy ( Name , Texture - > mName ) ;
strlwr ( Name ) ;
2017-05-29 22:31:24 +02:00
sprintf ( FileName , " parts/textures/%s.png " , Name ) ;
2013-08-09 06:57:18 +02:00
2018-02-17 20:32:29 +01:00
return Texture - > Load ( mLibraryDir . absoluteFilePath ( QLatin1String ( FileName ) ) ) ;
2018-02-17 20:34:15 +01:00
# else
return false ;
2018-02-17 20:32:29 +01:00
# endif
2013-08-09 06:57:18 +02:00
}
}
2017-07-02 02:12:09 +02:00
void lcPiecesLibrary : : ReleaseTexture ( lcTexture * Texture )
{
QMutexLocker LoadLock ( & mLoadMutex ) ;
if ( Texture - > Release ( ) = = 0 & & Texture - > IsTemporary ( ) )
{
mTextures . Remove ( Texture ) ;
delete Texture ;
}
}
2017-12-22 14:42:28 +01:00
void lcPiecesLibrary : : QueueTextureUpload ( lcTexture * Texture )
{
QMutexLocker Lock ( & mTextureMutex ) ;
mTextureUploads . push_back ( Texture ) ;
}
2018-09-30 04:45:21 +02:00
void lcPiecesLibrary : : UploadTextures ( lcContext * Context )
2017-12-22 14:42:28 +01:00
{
QMutexLocker Lock ( & mTextureMutex ) ;
for ( lcTexture * Texture : mTextureUploads )
2018-09-30 04:45:21 +02:00
Texture - > Upload ( Context ) ;
2017-12-22 14:42:28 +01:00
mTextureUploads . clear ( ) ;
}
2017-07-24 01:19:09 +02:00
bool lcPiecesLibrary : : LoadPrimitive ( lcLibraryPrimitive * Primitive )
2013-08-09 06:57:18 +02:00
{
2017-11-25 04:45:27 +01:00
mLoadMutex . lock ( ) ;
if ( Primitive - > mState = = lcPrimitiveState : : NOT_LOADED )
Primitive - > mState = lcPrimitiveState : : LOADING ;
else
{
mLoadMutex . unlock ( ) ;
while ( Primitive - > mState = = lcPrimitiveState : : LOADING )
lcSleeper : : msleep ( 5 ) ;
return Primitive - > mState = = lcPrimitiveState : : LOADED ;
}
mLoadMutex . unlock ( ) ;
2017-01-23 04:28:05 +01:00
2013-08-16 01:43:18 +02:00
lcArray < lcLibraryTextureMap > TextureStack ;
2013-08-09 06:57:18 +02:00
2014-05-08 00:58:59 +02:00
if ( mZipFiles [ LC_ZIPFILE_OFFICIAL ] )
2013-08-09 06:57:18 +02:00
{
2017-07-24 01:19:09 +02:00
lcLibraryPrimitive * LowPrimitive = nullptr ;
2015-05-24 06:36:25 +02:00
2019-06-02 04:54:09 +02:00
if ( Primitive - > mStud & & strncmp ( Primitive - > mName , " 8/ " , 2 ) ) // todo: this is currently the only place that uses mName so use mFileName instead. this should also be done for the loose file libraries.
2015-05-24 06:36:25 +02:00
{
char Name [ LC_PIECE_NAME_LEN ] ;
strcpy ( Name , " 8/ " ) ;
strcat ( Name , Primitive - > mName ) ;
2017-07-24 01:19:09 +02:00
LowPrimitive = FindPrimitive ( Name ) ;
2015-05-24 06:36:25 +02:00
}
2013-08-09 06:57:18 +02:00
lcMemFile PrimFile ;
2014-05-08 00:58:59 +02:00
if ( ! mZipFiles [ Primitive - > mZipFileType ] - > ExtractFile ( Primitive - > mZipFileIndex , PrimFile ) )
2013-08-09 06:57:18 +02:00
return false ;
2017-07-24 01:19:09 +02:00
if ( ! LowPrimitive )
2015-05-24 06:36:25 +02:00
{
2017-07-02 02:12:09 +02:00
if ( ! ReadMeshData ( PrimFile , lcMatrix44Identity ( ) , 16 , false , TextureStack , Primitive - > mMeshData , LC_MESHDATA_SHARED , true , nullptr , false ) )
2015-05-24 06:36:25 +02:00
return false ;
}
else
{
2017-07-02 02:12:09 +02:00
if ( ! ReadMeshData ( PrimFile , lcMatrix44Identity ( ) , 16 , false , TextureStack , Primitive - > mMeshData , LC_MESHDATA_HIGH , true , nullptr , false ) )
2015-05-24 06:36:25 +02:00
return false ;
if ( ! mZipFiles [ LowPrimitive - > mZipFileType ] - > ExtractFile ( LowPrimitive - > mZipFileIndex , PrimFile ) )
return false ;
TextureStack . RemoveAll ( ) ;
2017-07-02 02:12:09 +02:00
if ( ! ReadMeshData ( PrimFile , lcMatrix44Identity ( ) , 16 , false , TextureStack , Primitive - > mMeshData , LC_MESHDATA_LOW , true , nullptr , false ) )
2015-05-24 06:36:25 +02:00
return false ;
}
2013-08-09 06:57:18 +02:00
}
else
{
2019-06-02 04:54:09 +02:00
lcDiskFile PrimFile ( Primitive - > mFileName ) ;
2017-03-19 21:12:24 +01:00
2019-06-02 04:54:09 +02:00
if ( ! PrimFile . Open ( QIODevice : : ReadOnly ) | | ! ReadMeshData ( PrimFile , lcMatrix44Identity ( ) , 16 , false , TextureStack , Primitive - > mMeshData , LC_MESHDATA_SHARED , true , nullptr , false ) )
2013-08-09 06:57:18 +02:00
return false ;
}
2017-11-25 04:45:27 +01:00
mLoadMutex . lock ( ) ;
Primitive - > mState = lcPrimitiveState : : LOADED ;
mLoadMutex . unlock ( ) ;
2013-08-09 06:57:18 +02:00
return true ;
}
2017-12-02 21:22:04 +01:00
bool lcPiecesLibrary : : ReadMeshData ( lcFile & File , const lcMatrix44 & CurrentTransform , quint32 CurrentColorCode , bool InvertWinding , lcArray < lcLibraryTextureMap > & TextureStack , lcLibraryMeshData & MeshData , lcMeshDataType MeshDataType , bool Optimize , Project * CurrentProject , bool SearchProjectFolder )
2013-08-09 06:57:18 +02:00
{
char Buffer [ 1024 ] ;
char * Line ;
2017-02-21 17:09:13 +01:00
bool InvertNext = false ;
bool WindingCCW = ! InvertWinding ;
2013-08-09 06:57:18 +02:00
while ( File . ReadLine ( Buffer , sizeof ( Buffer ) ) )
{
2017-11-25 21:57:41 +01:00
if ( mCancelLoading )
return false ;
2017-12-02 21:22:04 +01:00
quint32 ColorCode , ColorCodeHex ;
2017-02-21 17:09:13 +01:00
bool LastToken = false ;
2013-08-09 06:57:18 +02:00
int LineType ;
Line = Buffer ;
if ( sscanf ( Line , " %d " , & LineType ) ! = 1 )
continue ;
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 + + ;
2017-02-21 17:09:13 +01:00
LastToken = ( * End = = 0 ) ;
2013-08-09 06:57:18 +02:00
* 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 ;
2018-01-18 00:14:24 +01:00
auto CleanTextureName = [ ] ( char * FileName )
2013-08-09 06:57:18 +02:00
{
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 ;
}
2018-01-18 00:14:24 +01:00
} ;
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 ) ;
2018-05-07 21:26:26 +02:00
Points [ 0 ] = lcMul31 ( Points [ 0 ] , CurrentTransform ) ;
Points [ 1 ] = lcMul31 ( Points [ 1 ] , CurrentTransform ) ;
Points [ 2 ] = lcMul31 ( Points [ 2 ] , CurrentTransform ) ;
2018-01-18 00:14:24 +01:00
CleanTextureName ( FileName ) ;
2013-08-09 06:57:18 +02:00
lcLibraryTextureMap & Map = TextureStack . Add ( ) ;
Map . Next = false ;
Map . Fallback = false ;
2017-07-02 02:12:09 +02:00
Map . Texture = FindTexture ( FileName , CurrentProject , SearchProjectFolder ) ;
2018-01-18 00:14:24 +01:00
Map . Type = lcLibraryTextureMapType : : PLANAR ;
2013-08-09 06:57:18 +02:00
for ( int EdgeIdx = 0 ; EdgeIdx < 2 ; EdgeIdx + + )
{
lcVector3 Normal = Points [ EdgeIdx + 1 ] - Points [ 0 ] ;
float Length = lcLength ( Normal ) ;
Normal / = Length ;
2019-03-17 21:17:11 +01:00
Map . Params . Planar . Planes [ EdgeIdx ] . x = Normal . x / Length ;
Map . Params . Planar . Planes [ EdgeIdx ] . y = Normal . y / Length ;
Map . Params . Planar . Planes [ EdgeIdx ] . z = Normal . z / Length ;
Map . Params . Planar . Planes [ EdgeIdx ] . w = - lcDot ( Normal , Points [ 0 ] ) / Length ;
2013-08-09 06:57:18 +02:00
}
}
2018-01-18 00:14:24 +01:00
else if ( ! strcmp ( Token , " CYLINDRICAL " ) )
{
Token + = 12 ;
char FileName [ LC_MAXPATH ] ;
lcVector3 Points [ 3 ] ;
float Angle ;
sscanf ( Token , " %f %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 , & Angle , FileName ) ;
2018-05-07 21:26:26 +02:00
Points [ 0 ] = lcMul31 ( Points [ 0 ] , CurrentTransform ) ;
Points [ 1 ] = lcMul31 ( Points [ 1 ] , CurrentTransform ) ;
Points [ 2 ] = lcMul31 ( Points [ 2 ] , CurrentTransform ) ;
2018-01-18 00:14:24 +01:00
CleanTextureName ( FileName ) ;
lcLibraryTextureMap & Map = TextureStack . Add ( ) ;
Map . Next = false ;
Map . Fallback = false ;
Map . Texture = FindTexture ( FileName , CurrentProject , SearchProjectFolder ) ;
2018-02-14 00:54:55 +01:00
Map . Type = lcLibraryTextureMapType : : CYLINDRICAL ;
2018-01-18 00:14:24 +01:00
lcVector3 Up = Points [ 0 ] - Points [ 1 ] ;
float UpLength = lcLength ( Up ) ;
lcVector3 Front = lcNormalize ( Points [ 2 ] - Points [ 1 ] ) ;
2018-02-14 00:54:55 +01:00
lcVector3 Plane1Normal = Up / UpLength ;
2018-02-19 19:47:10 +01:00
lcVector3 Plane2Normal = lcNormalize ( lcCross ( Front , Up ) ) ;
2019-03-17 21:17:11 +01:00
Map . Params . Cylindrical . FrontPlane = lcVector4 ( Front , - lcDot ( Front , Points [ 1 ] ) ) ;
Map . Params . Cylindrical . UpLength = UpLength ;
Map . Params . Cylindrical . Plane1 = lcVector4 ( Plane1Normal , - lcDot ( Plane1Normal , Points [ 1 ] ) ) ;
Map . Params . Cylindrical . Plane2 = lcVector4 ( Plane2Normal , - lcDot ( Plane2Normal , Points [ 1 ] ) ) ;
2018-02-14 00:54:55 +01:00
Map . Angle1 = 360.0f / Angle ;
2018-01-18 00:14:24 +01:00
}
else if ( ! strcmp ( Token , " SPHERICAL " ) )
{
2018-01-28 00:57:48 +01:00
Token + = 10 ;
char FileName [ LC_MAXPATH ] ;
lcVector3 Points [ 3 ] ;
float Angle1 , Angle2 ;
sscanf ( Token , " %f %f %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 , & Angle1 , & Angle2 , FileName ) ;
2018-05-07 21:26:26 +02:00
Points [ 0 ] = lcMul31 ( Points [ 0 ] , CurrentTransform ) ;
Points [ 1 ] = lcMul31 ( Points [ 1 ] , CurrentTransform ) ;
Points [ 2 ] = lcMul31 ( Points [ 2 ] , CurrentTransform ) ;
2018-01-28 00:57:48 +01:00
CleanTextureName ( FileName ) ;
lcLibraryTextureMap & Map = TextureStack . Add ( ) ;
Map . Next = false ;
Map . Fallback = false ;
Map . Texture = FindTexture ( FileName , CurrentProject , SearchProjectFolder ) ;
Map . Type = lcLibraryTextureMapType : : SPHERICAL ;
lcVector3 Front = lcNormalize ( Points [ 1 ] - Points [ 0 ] ) ;
lcVector3 Plane1Normal = lcNormalize ( lcCross ( Front , Points [ 2 ] - Points [ 0 ] ) ) ;
lcVector3 Plane2Normal = lcNormalize ( lcCross ( Plane1Normal , Front ) ) ;
2019-03-17 21:17:11 +01:00
Map . Params . Spherical . FrontPlane = lcVector4 ( Front , - lcDot ( Front , Points [ 0 ] ) ) ;
Map . Params . Spherical . Center = Points [ 0 ] ;
Map . Params . Spherical . Plane1 = lcVector4 ( Plane1Normal , - lcDot ( Plane1Normal , Points [ 0 ] ) ) ;
Map . Params . Spherical . Plane2 = lcVector4 ( Plane2Normal , - lcDot ( Plane2Normal , Points [ 0 ] ) ) ;
2018-01-28 00:57:48 +01:00
Map . Angle1 = 360.0f / Angle1 ;
Map . Angle2 = 180.0f / Angle2 ;
2018-01-18 00:14:24 +01:00
}
2013-08-09 06:57:18 +02:00
}
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 ;
}
2017-02-21 17:09:13 +01:00
else if ( ! strcmp ( Token , " BFC " ) )
{
while ( ! LastToken )
{
Token = End + 1 ;
while ( * Token & & * Token < = 32 )
Token + + ;
End = Token ;
while ( * End & & * End > 32 )
End + + ;
LastToken = ( * End = = 0 ) ;
* End = 0 ;
2017-02-21 21:57:25 +01:00
if ( ! strcmp ( Token , " INVERTNEXT " ) )
2017-02-21 17:09:13 +01:00
InvertNext = true ;
else if ( ! strcmp ( Token , " CCW " ) )
WindingCCW = ! InvertWinding ;
else if ( ! strcmp ( Token , " CW " ) )
WindingCCW = InvertWinding ;
}
}
2013-08-09 06:57:18 +02:00
else if ( ! strcmp ( Token , " !: " ) )
{
Token + = 3 ;
Line = Token ;
if ( ! TextureStack . GetSize ( ) )
continue ;
}
else
continue ;
}
if ( sscanf ( Line , " %d %d " , & LineType , & ColorCode ) ! = 2 )
continue ;
2016-08-22 03:11:32 +02:00
if ( LineType < 1 | | LineType > 5 )
2013-08-09 06:57:18 +02:00
continue ;
if ( ColorCode = = 0 )
{
sscanf ( Line , " %d %i " , & LineType , & ColorCodeHex ) ;
if ( ColorCode ! = ColorCodeHex )
ColorCode = ColorCodeHex | LC_COLOR_DIRECT ;
}
if ( ColorCode = = 16 )
ColorCode = CurrentColorCode ;
2017-04-14 02:26:40 +02:00
lcLibraryTextureMap * TextureMap = nullptr ;
2013-08-09 06:57:18 +02:00
if ( TextureStack . GetSize ( ) )
{
TextureMap = & TextureStack [ TextureStack . GetSize ( ) - 1 ] ;
2018-03-17 20:21:38 +01:00
if ( TextureMap - > Texture )
{
if ( TextureMap - > Fallback )
continue ;
}
else
{
if ( ! TextureMap - > Fallback )
continue ;
TextureMap = nullptr ;
}
2013-08-09 06:57:18 +02:00
}
int Dummy ;
lcVector3 Points [ 4 ] ;
switch ( LineType )
{
case 1 :
{
2016-05-28 22:30:23 +02:00
char OriginalFileName [ LC_MAXPATH ] ;
2013-08-09 06:57:18 +02:00
float fm [ 12 ] ;
2016-05-28 22:30:23 +02:00
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 ] , OriginalFileName ) ;
char FileName [ LC_MAXPATH ] ;
strcpy ( FileName , OriginalFileName ) ;
2013-08-09 06:57:18 +02:00
char * Ch ;
for ( Ch = FileName ; * Ch ; Ch + + )
{
if ( * Ch > = ' a ' & & * Ch < = ' z ' )
* Ch = * Ch + ' A ' - ' a ' ;
else if ( * Ch = = ' \\ ' )
* Ch = ' / ' ;
}
2018-01-28 04:45:06 +01:00
lcLibraryPrimitive * Primitive = ! TextureMap ? FindPrimitive ( FileName ) : nullptr ;
2013-08-09 06:57:18 +02:00
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 ) ;
2017-02-21 17:09:13 +01:00
bool Mirror = IncludeTransform . Determinant ( ) < 0.0f ;
2013-08-09 06:57:18 +02:00
2017-07-24 01:19:09 +02:00
if ( Primitive )
2013-08-09 06:57:18 +02:00
{
2017-11-25 04:45:27 +01:00
if ( Primitive - > mState ! = lcPrimitiveState : : LOADED & & ! LoadPrimitive ( Primitive ) )
2017-02-21 17:09:13 +01:00
break ;
2013-08-09 06:57:18 +02:00
if ( Primitive - > mStud )
2017-03-01 17:36:46 +01:00
MeshData . AddMeshDataNoDuplicateCheck ( Primitive - > mMeshData , IncludeTransform , ColorCode , Mirror ^ InvertNext , InvertNext , TextureMap , MeshDataType ) ;
2013-08-09 06:57:18 +02:00
else if ( ! Primitive - > mSubFile )
2016-02-29 21:13:54 +01:00
{
if ( Optimize )
2017-03-01 17:36:46 +01:00
MeshData . AddMeshData ( Primitive - > mMeshData , IncludeTransform , ColorCode , Mirror ^ InvertNext , InvertNext , TextureMap , MeshDataType ) ;
2016-02-29 21:13:54 +01:00
else
2017-03-01 17:36:46 +01:00
MeshData . AddMeshDataNoDuplicateCheck ( Primitive - > mMeshData , IncludeTransform , ColorCode , Mirror ^ InvertNext , InvertNext , TextureMap , MeshDataType ) ;
2016-02-29 21:13:54 +01:00
}
2013-08-09 06:57:18 +02:00
else
{
2014-05-08 00:58:59 +02:00
if ( mZipFiles [ LC_ZIPFILE_OFFICIAL ] )
2013-08-09 06:57:18 +02:00
{
lcMemFile IncludeFile ;
2017-02-21 17:09:13 +01:00
if ( mZipFiles [ Primitive - > mZipFileType ] - > ExtractFile ( Primitive - > mZipFileIndex , IncludeFile ) )
2017-07-02 02:12:09 +02:00
ReadMeshData ( IncludeFile , IncludeTransform , ColorCode , Mirror ^ InvertNext , TextureStack , MeshData , MeshDataType , Optimize , CurrentProject , SearchProjectFolder ) ;
2013-08-09 06:57:18 +02:00
}
else
{
2019-06-02 04:54:09 +02:00
lcDiskFile IncludeFile ( Primitive - > mFileName ) ;
if ( IncludeFile . Open ( QIODevice : : ReadOnly ) )
2017-07-02 02:12:09 +02:00
ReadMeshData ( IncludeFile , IncludeTransform , ColorCode , Mirror ^ InvertNext , TextureStack , MeshData , MeshDataType , Optimize , CurrentProject , SearchProjectFolder ) ;
2013-08-09 06:57:18 +02:00
}
}
}
else
{
2017-07-24 04:35:18 +02:00
const auto PieceIt = mPieces . find ( FileName ) ;
2013-08-09 06:57:18 +02:00
2017-07-24 04:35:18 +02:00
if ( PieceIt ! = mPieces . end ( ) )
{
PieceInfo * Info = PieceIt - > second ;
2013-08-09 06:57:18 +02:00
2016-09-26 02:15:30 +02:00
if ( mZipFiles [ LC_ZIPFILE_OFFICIAL ] & & Info - > mZipFileType ! = LC_NUM_ZIPFILES )
2013-08-09 06:57:18 +02:00
{
lcMemFile IncludeFile ;
2016-05-28 22:30:23 +02:00
if ( mZipFiles [ Info - > mZipFileType ] - > ExtractFile ( Info - > mZipFileIndex , IncludeFile ) )
2017-07-02 02:12:09 +02:00
ReadMeshData ( IncludeFile , IncludeTransform , ColorCode , Mirror ^ InvertNext , TextureStack , MeshData , MeshDataType , Optimize , CurrentProject , SearchProjectFolder ) ;
2013-08-09 06:57:18 +02:00
}
else
{
lcDiskFile IncludeFile ;
2017-03-19 21:12:24 +01:00
bool Found = false ;
2013-08-09 06:57:18 +02:00
2017-03-19 21:12:24 +01:00
if ( mHasUnofficial )
{
2017-07-27 18:21:55 +02:00
sprintf ( FileName , " unofficial/parts/%s " , Info - > mFileName ) ;
2017-05-29 22:31:24 +02:00
IncludeFile . SetFileName ( mLibraryDir . absoluteFilePath ( QLatin1String ( FileName ) ) ) ;
Found = IncludeFile . Open ( QIODevice : : ReadOnly ) ;
2017-03-19 21:12:24 +01:00
}
if ( ! Found )
{
2017-07-27 18:21:55 +02:00
sprintf ( FileName , " parts/%s " , Info - > mFileName ) ;
2017-05-29 22:31:24 +02:00
IncludeFile . SetFileName ( mLibraryDir . absoluteFilePath ( QLatin1String ( FileName ) ) ) ;
Found = IncludeFile . Open ( QIODevice : : ReadOnly ) ;
2017-03-19 21:12:24 +01:00
}
2013-08-09 06:57:18 +02:00
2017-03-19 21:12:24 +01:00
if ( Found )
2017-07-02 02:12:09 +02:00
ReadMeshData ( IncludeFile , IncludeTransform , ColorCode , Mirror ^ InvertNext , TextureStack , MeshData , MeshDataType , Optimize , CurrentProject , SearchProjectFolder ) ;
2013-08-09 06:57:18 +02:00
}
break ;
}
2018-01-28 04:45:06 +01:00
else
{
bool Found = false ;
if ( mZipFiles [ LC_ZIPFILE_OFFICIAL ] )
{
lcMemFile IncludeFile ;
auto LoadIncludeFile = [ & IncludeFile , & FileName , this ] ( const char * Folder , int ZipFileIndex )
{
char IncludeFileName [ LC_MAXPATH ] ;
sprintf ( IncludeFileName , Folder , FileName ) ;
return mZipFiles [ ZipFileIndex ] - > ExtractFile ( IncludeFileName , IncludeFile ) ;
} ;
if ( mHasUnofficial )
{
Found = LoadIncludeFile ( " parts/%s " , LC_ZIPFILE_UNOFFICIAL ) ;
if ( ! Found )
Found = LoadIncludeFile ( " p/%s " , LC_ZIPFILE_UNOFFICIAL ) ;
}
if ( ! Found )
{
Found = LoadIncludeFile ( " ldraw/parts/%s " , LC_ZIPFILE_OFFICIAL ) ;
if ( ! Found )
Found = LoadIncludeFile ( " ldraw/p/%s " , LC_ZIPFILE_OFFICIAL ) ;
}
if ( Found )
ReadMeshData ( IncludeFile , IncludeTransform , ColorCode , Mirror ^ InvertNext , TextureStack , MeshData , MeshDataType , Optimize , CurrentProject , SearchProjectFolder ) ;
}
else
{
lcDiskFile IncludeFile ;
auto LoadIncludeFile = [ & IncludeFile , & FileName , this ] ( const char * Folder )
{
char IncludeFileName [ LC_MAXPATH ] ;
sprintf ( IncludeFileName , Folder , FileName ) ;
IncludeFile . SetFileName ( mLibraryDir . absoluteFilePath ( QLatin1String ( IncludeFileName ) ) ) ;
2018-02-01 21:48:31 +01:00
if ( IncludeFile . Open ( QIODevice : : ReadOnly ) )
return true ;
2018-02-17 20:32:29 +01:00
# if defined(Q_OS_MACOS) || defined(Q_OS_LINUX)
2018-02-01 21:48:31 +01:00
// todo: instead of using strlwr, search the parts/primitive lists and get the file name from there
strlwr ( IncludeFileName ) ;
IncludeFile . SetFileName ( mLibraryDir . absoluteFilePath ( QLatin1String ( IncludeFileName ) ) ) ;
2018-01-28 04:45:06 +01:00
return IncludeFile . Open ( QIODevice : : ReadOnly ) ;
2018-02-17 20:32:29 +01:00
# else
return false ;
# endif
2018-01-28 04:45:06 +01:00
} ;
if ( mHasUnofficial )
{
Found = LoadIncludeFile ( " unofficial/parts/%s " ) ;
if ( ! Found )
Found = LoadIncludeFile ( " unofficial/p/%s " ) ;
}
if ( ! Found )
{
Found = LoadIncludeFile ( " parts/%s " ) ;
if ( ! Found )
Found = LoadIncludeFile ( " p/%s " ) ;
}
if ( Found )
ReadMeshData ( IncludeFile , IncludeTransform , ColorCode , Mirror ^ InvertNext , TextureStack , MeshData , MeshDataType , Optimize , CurrentProject , SearchProjectFolder ) ;
}
}
2013-08-09 06:57:18 +02:00
}
} break ;
case 2 :
2017-02-21 17:09:13 +01:00
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 ) ;
2013-08-09 06:57:18 +02:00
2017-02-21 17:09:13 +01:00
Points [ 0 ] = lcMul31 ( Points [ 0 ] , CurrentTransform ) ;
Points [ 1 ] = lcMul31 ( Points [ 1 ] , CurrentTransform ) ;
2013-08-09 06:57:18 +02:00
2017-02-21 17:09:13 +01:00
if ( TextureMap )
{
MeshData . AddTexturedLine ( MeshDataType , LineType , ColorCode , WindingCCW , * TextureMap , Points , Optimize ) ;
2013-08-09 06:57:18 +02:00
2017-02-21 17:09:13 +01:00
if ( TextureMap - > Next )
TextureStack . RemoveIndex ( TextureStack . GetSize ( ) - 1 ) ;
}
else
MeshData . AddLine ( MeshDataType , LineType , ColorCode , WindingCCW , Points , Optimize ) ;
break ;
2013-08-09 06:57:18 +02:00
case 3 :
2017-02-21 17:09:13 +01:00
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 ) ;
2013-08-09 06:57:18 +02:00
2017-02-21 17:09:13 +01:00
Points [ 0 ] = lcMul31 ( Points [ 0 ] , CurrentTransform ) ;
Points [ 1 ] = lcMul31 ( Points [ 1 ] , CurrentTransform ) ;
Points [ 2 ] = lcMul31 ( Points [ 2 ] , CurrentTransform ) ;
2013-08-09 06:57:18 +02:00
2017-02-21 17:09:13 +01:00
if ( TextureMap )
{
MeshData . AddTexturedLine ( MeshDataType , LineType , ColorCode , WindingCCW , * TextureMap , Points , Optimize ) ;
2013-08-09 06:57:18 +02:00
2017-02-21 17:09:13 +01:00
if ( TextureMap - > Next )
TextureStack . RemoveIndex ( TextureStack . GetSize ( ) - 1 ) ;
}
else
MeshData . AddLine ( MeshDataType , LineType , ColorCode , WindingCCW , Points , Optimize ) ;
break ;
2013-08-09 06:57:18 +02:00
case 4 :
2017-02-21 17:09:13 +01:00
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 ) ;
2013-08-09 06:57:18 +02:00
2017-02-21 17:09:13 +01:00
Points [ 0 ] = lcMul31 ( Points [ 0 ] , CurrentTransform ) ;
Points [ 1 ] = lcMul31 ( Points [ 1 ] , CurrentTransform ) ;
Points [ 2 ] = lcMul31 ( Points [ 2 ] , CurrentTransform ) ;
Points [ 3 ] = lcMul31 ( Points [ 3 ] , CurrentTransform ) ;
2013-08-09 06:57:18 +02:00
2017-02-21 17:09:13 +01:00
if ( TextureMap )
{
MeshData . AddTexturedLine ( MeshDataType , LineType , ColorCode , WindingCCW , * TextureMap , Points , Optimize ) ;
2013-08-09 06:57:18 +02:00
2017-02-21 17:09:13 +01:00
if ( TextureMap - > Next )
TextureStack . RemoveIndex ( TextureStack . GetSize ( ) - 1 ) ;
}
else
MeshData . AddLine ( MeshDataType , LineType , ColorCode , WindingCCW , Points , Optimize ) ;
break ;
2016-08-22 03:11:32 +02:00
case 5 :
2017-02-21 17:09:13 +01:00
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 ) ;
2016-08-22 03:11:32 +02:00
2017-02-21 17:09:13 +01:00
Points [ 0 ] = lcMul31 ( Points [ 0 ] , CurrentTransform ) ;
Points [ 1 ] = lcMul31 ( Points [ 1 ] , CurrentTransform ) ;
Points [ 2 ] = lcMul31 ( Points [ 2 ] , CurrentTransform ) ;
Points [ 3 ] = lcMul31 ( Points [ 3 ] , CurrentTransform ) ;
2016-08-22 03:11:32 +02:00
2017-02-21 17:09:13 +01:00
MeshData . AddLine ( MeshDataType , LineType , ColorCode , WindingCCW , Points , Optimize ) ;
break ;
2013-08-09 06:57:18 +02:00
}
2017-02-21 17:09:13 +01:00
InvertNext = false ;
2013-08-09 06:57:18 +02:00
}
return true ;
}
2015-02-23 01:50:37 +01:00
void lcLibraryMeshData : : ResequenceQuad ( int * Indices , int a , int b , int c , int d )
2013-08-09 06:57:18 +02:00
{
2015-02-23 01:50:37 +01:00
Indices [ 0 ] = a ;
Indices [ 1 ] = b ;
Indices [ 2 ] = c ;
Indices [ 3 ] = d ;
2013-08-09 06:57:18 +02:00
}
2015-02-23 01:50:37 +01:00
void lcLibraryMeshData : : TestQuad ( int * QuadIndices , const lcVector3 * Vertices )
2013-08-09 06:57:18 +02:00
{
lcVector3 v01 = Vertices [ 1 ] - Vertices [ 0 ] ;
lcVector3 v02 = Vertices [ 2 ] - Vertices [ 0 ] ;
lcVector3 v03 = Vertices [ 3 ] - Vertices [ 0 ] ;
lcVector3 cp1 = lcCross ( v01 , v02 ) ;
lcVector3 cp2 = lcCross ( v02 , v03 ) ;
if ( lcDot ( cp1 , cp2 ) > 0.0f )
return ;
lcVector3 v12 = Vertices [ 2 ] - Vertices [ 1 ] ;
lcVector3 v13 = Vertices [ 3 ] - Vertices [ 1 ] ;
lcVector3 v23 = Vertices [ 3 ] - Vertices [ 2 ] ;
if ( lcDot ( lcCross ( v12 , v01 ) , lcCross ( v01 , v13 ) ) > 0.0f )
{
if ( - lcDot ( lcCross ( v02 , v12 ) , lcCross ( v12 , v23 ) ) > 0.0f )
2015-02-23 01:50:37 +01:00
ResequenceQuad ( QuadIndices , 1 , 2 , 3 , 0 ) ;
2013-08-09 06:57:18 +02:00
else
2015-02-23 01:50:37 +01:00
ResequenceQuad ( QuadIndices , 0 , 3 , 1 , 2 ) ;
2013-08-09 06:57:18 +02:00
}
else
{
if ( - lcDot ( lcCross ( v02 , v12 ) , lcCross ( v12 , v23 ) ) > 0.0f )
2015-02-23 01:50:37 +01:00
ResequenceQuad ( QuadIndices , 0 , 1 , 3 , 2 ) ;
2013-08-09 06:57:18 +02:00
else
2015-02-23 01:50:37 +01:00
ResequenceQuad ( QuadIndices , 1 , 2 , 3 , 0 ) ;
2013-08-09 06:57:18 +02:00
}
}
2017-12-02 21:22:04 +01:00
lcLibraryMeshSection * lcLibraryMeshData : : AddSection ( lcMeshDataType MeshDataType , lcMeshPrimitiveType PrimitiveType , quint32 ColorCode , lcTexture * Texture )
2013-08-09 06:57:18 +02:00
{
2015-05-24 06:36:25 +02:00
lcArray < lcLibraryMeshSection * > & Sections = mSections [ MeshDataType ] ;
2016-04-11 17:45:08 +02:00
lcLibraryMeshSection * Section ;
2013-08-09 06:57:18 +02:00
2016-04-11 17:45:08 +02:00
for ( int SectionIdx = 0 ; SectionIdx < Sections . GetSize ( ) ; SectionIdx + + )
2013-08-09 06:57:18 +02:00
{
2015-05-24 06:36:25 +02:00
Section = Sections [ SectionIdx ] ;
2013-08-09 06:57:18 +02:00
2016-04-11 17:45:08 +02:00
if ( Section - > mColor = = ColorCode & & Section - > mPrimitiveType = = PrimitiveType & & Section - > mTexture = = Texture )
return Section ;
2013-08-09 06:57:18 +02:00
}
2016-04-11 17:45:08 +02:00
Section = new lcLibraryMeshSection ( PrimitiveType , ColorCode , Texture ) ;
Sections . Add ( Section ) ;
2013-08-09 06:57:18 +02:00
2016-04-11 17:45:08 +02:00
return Section ;
}
2017-02-28 01:03:12 +01:00
void lcLibraryMeshData : : AddVertices ( lcMeshDataType MeshDataType , int VertexCount , int * BaseVertex , lcLibraryMeshVertex * * VertexBuffer )
2016-04-11 17:45:08 +02:00
{
2017-02-28 01:03:12 +01:00
lcArray < lcLibraryMeshVertex > & Vertices = mVertices [ MeshDataType ] ;
2016-04-11 17:45:08 +02:00
int CurrentSize = Vertices . GetSize ( ) ;
Vertices . SetSize ( CurrentSize + VertexCount ) ;
* BaseVertex = CurrentSize ;
* VertexBuffer = & Vertices [ CurrentSize ] ;
}
2018-01-20 21:04:50 +01:00
const float lcDistanceEpsilon = 0.01f ; // Maximum value for 50591.dat
const float lcTexCoordEpsilon = 0.01f ;
inline bool lcCompareVertices ( const lcVector3 & Position1 , const lcVector3 & Position2 )
{
return fabsf ( Position1 . x - Position2 . x ) < lcDistanceEpsilon & & fabsf ( Position1 . y - Position2 . y ) < lcDistanceEpsilon & & fabsf ( Position1 . z - Position2 . z ) < lcDistanceEpsilon ;
}
inline bool lcCompareVertices ( const lcVector3 & Position1 , const lcVector2 & TexCoord1 , const lcVector3 & Position2 , const lcVector2 & TexCoord2 )
{
return fabsf ( Position1 . x - Position2 . x ) < lcDistanceEpsilon & & fabsf ( Position1 . y - Position2 . y ) < lcDistanceEpsilon & & fabsf ( Position1 . z - Position2 . z ) < lcDistanceEpsilon & &
fabsf ( TexCoord1 . x - TexCoord2 . x ) < lcTexCoordEpsilon & & fabsf ( TexCoord1 . y - TexCoord2 . y ) < lcTexCoordEpsilon ;
}
2017-12-02 21:22:04 +01:00
quint32 lcLibraryMeshData : : AddVertex ( lcMeshDataType MeshDataType , const lcVector3 & Position , bool Optimize )
2017-02-28 01:03:12 +01:00
{
lcArray < lcLibraryMeshVertex > & VertexArray = mVertices [ MeshDataType ] ;
if ( Optimize )
{
for ( int VertexIdx = VertexArray . GetSize ( ) - 1 ; VertexIdx > = 0 ; VertexIdx - - )
{
lcLibraryMeshVertex & Vertex = VertexArray [ VertexIdx ] ;
2018-01-20 21:04:50 +01:00
if ( lcCompareVertices ( Position , Vertex . Position ) )
2019-05-28 01:07:20 +02:00
{
Vertex . Usage | = LC_LIBRARY_VERTEX_UNTEXTURED ;
2017-02-28 01:03:12 +01:00
return VertexIdx ;
2019-05-28 01:07:20 +02:00
}
2017-02-28 01:03:12 +01:00
}
}
lcLibraryMeshVertex & Vertex = VertexArray . Add ( ) ;
Vertex . Position = Position ;
Vertex . Normal = lcVector3 ( 0.0f , 0.0f , 0.0f ) ;
Vertex . NormalWeight = 0.0f ;
2019-05-28 01:07:20 +02:00
Vertex . TexCoord = lcVector2 ( 0.0f , 0.0f ) ;
Vertex . Usage = LC_LIBRARY_VERTEX_UNTEXTURED ;
2017-02-28 01:03:12 +01:00
return VertexArray . GetSize ( ) - 1 ;
}
2017-12-02 21:22:04 +01:00
quint32 lcLibraryMeshData : : AddVertex ( lcMeshDataType MeshDataType , const lcVector3 & Position , const lcVector3 & Normal , bool Optimize )
2017-02-28 01:03:12 +01:00
{
lcArray < lcLibraryMeshVertex > & VertexArray = mVertices [ MeshDataType ] ;
if ( Optimize )
{
for ( int VertexIdx = VertexArray . GetSize ( ) - 1 ; VertexIdx > = 0 ; VertexIdx - - )
{
lcLibraryMeshVertex & Vertex = VertexArray [ VertexIdx ] ;
2018-01-20 21:04:50 +01:00
if ( lcCompareVertices ( Position , Vertex . Position ) )
2017-02-28 01:03:12 +01:00
{
if ( Vertex . NormalWeight = = 0.0f )
{
Vertex . Normal = Normal ;
Vertex . NormalWeight = 1.0f ;
2019-05-28 01:07:20 +02:00
Vertex . Usage | = LC_LIBRARY_VERTEX_UNTEXTURED ;
2017-02-28 01:03:12 +01:00
return VertexIdx ;
}
2017-08-25 01:51:45 +02:00
else if ( lcDot ( Normal , Vertex . Normal ) > 0.707f )
2017-02-28 01:03:12 +01:00
{
Vertex . Normal = lcNormalize ( Vertex . Normal * Vertex . NormalWeight + Normal ) ;
Vertex . NormalWeight + = 1.0f ;
2019-05-28 01:07:20 +02:00
Vertex . Usage | = LC_LIBRARY_VERTEX_UNTEXTURED ;
2017-02-28 01:03:12 +01:00
return VertexIdx ;
}
}
}
}
lcLibraryMeshVertex & Vertex = VertexArray . Add ( ) ;
Vertex . Position = Position ;
Vertex . Normal = Normal ;
Vertex . NormalWeight = 1.0f ;
2019-05-28 01:07:20 +02:00
Vertex . TexCoord = lcVector2 ( 0.0f , 0.0f ) ;
Vertex . Usage = LC_LIBRARY_VERTEX_UNTEXTURED ;
2017-02-28 01:03:12 +01:00
return VertexArray . GetSize ( ) - 1 ;
}
2017-12-02 21:22:04 +01:00
quint32 lcLibraryMeshData : : AddTexturedVertex ( lcMeshDataType MeshDataType , const lcVector3 & Position , const lcVector2 & TexCoord , bool Optimize )
2017-02-28 01:03:12 +01:00
{
2019-05-28 01:07:20 +02:00
mHasTextures = true ;
lcArray < lcLibraryMeshVertex > & VertexArray = mVertices [ MeshDataType ] ;
2017-02-28 01:03:12 +01:00
if ( Optimize )
{
for ( int VertexIdx = VertexArray . GetSize ( ) - 1 ; VertexIdx > = 0 ; VertexIdx - - )
{
2019-05-28 01:07:20 +02:00
lcLibraryMeshVertex & Vertex = VertexArray [ VertexIdx ] ;
2017-02-28 01:03:12 +01:00
2019-05-28 01:07:20 +02:00
if ( Vertex . Usage & LC_LIBRARY_VERTEX_TEXTURED )
{
if ( lcCompareVertices ( Position , TexCoord , Vertex . Position , Vertex . TexCoord ) )
return VertexIdx ;
}
else
{
if ( lcCompareVertices ( Position , Vertex . Position ) )
{
Vertex . TexCoord = TexCoord ;
Vertex . Usage | = LC_LIBRARY_VERTEX_TEXTURED ;
return VertexIdx ;
}
}
2017-02-28 01:03:12 +01:00
}
}
2019-05-28 01:07:20 +02:00
lcLibraryMeshVertex & Vertex = VertexArray . Add ( ) ;
2017-02-28 01:03:12 +01:00
Vertex . Position = Position ;
Vertex . Normal = lcVector3 ( 0.0f , 0.0f , 0.0f ) ;
Vertex . NormalWeight = 0.0f ;
Vertex . TexCoord = TexCoord ;
2019-05-28 01:07:20 +02:00
Vertex . Usage = LC_LIBRARY_VERTEX_TEXTURED ;
2017-02-28 01:03:12 +01:00
return VertexArray . GetSize ( ) - 1 ;
}
2017-12-02 21:22:04 +01:00
quint32 lcLibraryMeshData : : AddTexturedVertex ( lcMeshDataType MeshDataType , const lcVector3 & Position , const lcVector3 & Normal , const lcVector2 & TexCoord , bool Optimize )
2017-02-28 01:03:12 +01:00
{
2019-05-28 01:07:20 +02:00
mHasTextures = true ;
lcArray < lcLibraryMeshVertex > & VertexArray = mVertices [ MeshDataType ] ;
2017-02-28 01:03:12 +01:00
if ( Optimize )
{
for ( int VertexIdx = VertexArray . GetSize ( ) - 1 ; VertexIdx > = 0 ; VertexIdx - - )
{
2019-05-28 01:07:20 +02:00
lcLibraryMeshVertex & Vertex = VertexArray [ VertexIdx ] ;
2017-02-28 01:03:12 +01:00
2019-05-28 01:07:20 +02:00
if ( Vertex . Usage & LC_LIBRARY_VERTEX_TEXTURED )
2017-02-28 01:03:12 +01:00
{
2019-05-28 01:07:20 +02:00
if ( lcCompareVertices ( Position , TexCoord , Vertex . Position , Vertex . TexCoord ) )
2017-02-28 01:03:12 +01:00
{
2019-05-28 01:07:20 +02:00
if ( Vertex . NormalWeight = = 0.0f )
{
Vertex . Normal = Normal ;
Vertex . NormalWeight = 1.0f ;
return VertexIdx ;
}
else if ( lcDot ( Normal , Vertex . Normal ) > 0.707f )
{
Vertex . Normal = lcNormalize ( Vertex . Normal * Vertex . NormalWeight + Normal ) ;
Vertex . NormalWeight + = 1.0f ;
return VertexIdx ;
}
2017-02-28 01:03:12 +01:00
}
2019-05-28 01:07:20 +02:00
}
else
{
if ( lcCompareVertices ( Position , Vertex . Position ) )
2017-02-28 01:03:12 +01:00
{
2019-05-28 01:07:20 +02:00
if ( Vertex . NormalWeight = = 0.0f )
{
Vertex . Normal = Normal ;
Vertex . NormalWeight = 1.0f ;
Vertex . TexCoord = TexCoord ;
Vertex . Usage | = LC_LIBRARY_VERTEX_TEXTURED ;
return VertexIdx ;
}
else if ( lcDot ( Normal , Vertex . Normal ) > 0.707f )
{
Vertex . Normal = lcNormalize ( Vertex . Normal * Vertex . NormalWeight + Normal ) ;
Vertex . NormalWeight + = 1.0f ;
Vertex . TexCoord = TexCoord ;
Vertex . Usage | = LC_LIBRARY_VERTEX_TEXTURED ;
return VertexIdx ;
}
2017-02-28 01:03:12 +01:00
}
}
}
}
2019-05-28 01:07:20 +02:00
lcLibraryMeshVertex & Vertex = VertexArray . Add ( ) ;
2017-02-28 01:03:12 +01:00
Vertex . Position = Position ;
Vertex . Normal = Normal ;
Vertex . NormalWeight = 1.0f ;
Vertex . TexCoord = TexCoord ;
2019-05-28 01:07:20 +02:00
Vertex . Usage = LC_LIBRARY_VERTEX_TEXTURED ;
2017-02-28 01:03:12 +01:00
return VertexArray . GetSize ( ) - 1 ;
}
2017-12-02 21:22:04 +01:00
void lcLibraryMeshData : : AddIndices ( lcMeshDataType MeshDataType , lcMeshPrimitiveType PrimitiveType , quint32 ColorCode , int IndexCount , quint32 * * IndexBuffer )
2016-04-11 17:45:08 +02:00
{
2017-04-14 02:26:40 +02:00
lcLibraryMeshSection * Section = AddSection ( MeshDataType , PrimitiveType , ColorCode , nullptr ) ;
2017-12-02 21:22:04 +01:00
lcArray < quint32 > & Indices = Section - > mIndices ;
2016-04-11 17:45:08 +02:00
int CurrentSize = Indices . GetSize ( ) ;
Indices . SetSize ( CurrentSize + IndexCount ) ;
* IndexBuffer = & Indices [ CurrentSize ] ;
}
2017-12-02 21:22:04 +01:00
void lcLibraryMeshData : : AddLine ( lcMeshDataType MeshDataType , int LineType , quint32 ColorCode , bool WindingCCW , const lcVector3 * Vertices , bool Optimize )
2016-04-11 17:45:08 +02:00
{
2016-08-22 03:11:32 +02:00
lcMeshPrimitiveType PrimitiveTypes [ 4 ] = { LC_MESH_LINES , LC_MESH_TRIANGLES , LC_MESH_TRIANGLES , LC_MESH_CONDITIONAL_LINES } ;
lcMeshPrimitiveType PrimitiveType = PrimitiveTypes [ LineType - 2 ] ;
2017-04-14 02:26:40 +02:00
lcLibraryMeshSection * Section = AddSection ( MeshDataType , PrimitiveType , ColorCode , nullptr ) ;
2013-08-09 06:57:18 +02:00
2015-02-23 01:50:37 +01:00
int QuadIndices [ 4 ] = { 0 , 1 , 2 , 3 } ;
2013-08-09 06:57:18 +02:00
int Indices [ 4 ] = { - 1 , - 1 , - 1 , - 1 } ;
2017-02-28 01:03:12 +01:00
if ( LineType = = 3 | | LineType = = 4 )
2013-08-09 06:57:18 +02:00
{
2017-02-28 01:03:12 +01:00
if ( LineType = = 4 )
TestQuad ( QuadIndices , Vertices ) ;
2013-08-09 06:57:18 +02:00
2017-03-01 00:20:34 +01:00
lcVector3 Normal = lcNormalize ( lcCross ( Vertices [ 1 ] - Vertices [ 0 ] , Vertices [ 2 ] - Vertices [ 0 ] ) ) ;
2016-05-29 04:46:34 +02:00
2017-02-28 01:03:12 +01:00
if ( ! WindingCCW )
Normal = - Normal ;
2013-08-09 06:57:18 +02:00
2017-02-28 01:03:12 +01:00
for ( int IndexIdx = 0 ; IndexIdx < lcMin ( LineType , 4 ) ; IndexIdx + + )
{
const lcVector3 & Position = Vertices [ QuadIndices [ IndexIdx ] ] ;
Indices [ IndexIdx ] = AddVertex ( MeshDataType , Position , Normal , Optimize ) ;
}
}
else
{
for ( int IndexIdx = 0 ; IndexIdx < lcMin ( LineType , 4 ) ; IndexIdx + + )
2013-08-09 06:57:18 +02:00
{
2017-02-28 01:03:12 +01:00
const lcVector3 & Position = Vertices [ QuadIndices [ IndexIdx ] ] ;
Indices [ IndexIdx ] = AddVertex ( MeshDataType , Position , Optimize ) ;
2013-08-09 06:57:18 +02:00
}
}
switch ( LineType )
{
2016-08-22 03:11:32 +02:00
case 5 :
if ( Indices [ 0 ] ! = Indices [ 1 ] & & Indices [ 0 ] ! = Indices [ 2 ] & & Indices [ 0 ] ! = Indices [ 3 ] & & Indices [ 1 ] ! = Indices [ 2 ] & & Indices [ 1 ] ! = Indices [ 3 ] & & Indices [ 2 ] ! = Indices [ 3 ] )
{
Section - > mIndices . Add ( Indices [ 0 ] ) ;
Section - > mIndices . Add ( Indices [ 1 ] ) ;
Section - > mIndices . Add ( Indices [ 2 ] ) ;
Section - > mIndices . Add ( Indices [ 3 ] ) ;
}
break ;
2013-08-09 06:57:18 +02:00
case 4 :
if ( Indices [ 0 ] ! = Indices [ 2 ] & & Indices [ 0 ] ! = Indices [ 3 ] & & Indices [ 2 ] ! = Indices [ 3 ] )
{
2017-02-21 17:09:13 +01:00
if ( WindingCCW )
{
Section - > mIndices . Add ( Indices [ 2 ] ) ;
Section - > mIndices . Add ( Indices [ 3 ] ) ;
Section - > mIndices . Add ( Indices [ 0 ] ) ;
}
else
{
Section - > mIndices . Add ( Indices [ 0 ] ) ;
Section - > mIndices . Add ( Indices [ 3 ] ) ;
Section - > mIndices . Add ( Indices [ 2 ] ) ;
}
2013-08-09 06:57:18 +02:00
}
2018-09-24 20:29:05 +02:00
Q_FALLTHROUGH ( ) ;
2013-08-09 06:57:18 +02:00
case 3 :
if ( Indices [ 0 ] ! = Indices [ 1 ] & & Indices [ 0 ] ! = Indices [ 2 ] & & Indices [ 1 ] ! = Indices [ 2 ] )
{
2017-02-21 17:09:13 +01:00
if ( WindingCCW )
{
Section - > mIndices . Add ( Indices [ 0 ] ) ;
Section - > mIndices . Add ( Indices [ 1 ] ) ;
Section - > mIndices . Add ( Indices [ 2 ] ) ;
}
else
{
Section - > mIndices . Add ( Indices [ 2 ] ) ;
Section - > mIndices . Add ( Indices [ 1 ] ) ;
Section - > mIndices . Add ( Indices [ 0 ] ) ;
}
2013-08-09 06:57:18 +02:00
}
break ;
2016-08-22 03:11:32 +02:00
2013-08-09 06:57:18 +02:00
case 2 :
if ( Indices [ 0 ] ! = Indices [ 1 ] )
{
Section - > mIndices . Add ( Indices [ 0 ] ) ;
Section - > mIndices . Add ( Indices [ 1 ] ) ;
}
break ;
}
}
2018-01-28 04:45:06 +01:00
void lcLibraryMeshData : : AddTexturedLine ( lcMeshDataType MeshDataType , int LineType , quint32 ColorCode , bool WindingCCW , const lcLibraryTextureMap & TextureMap , const lcVector3 * Vertices , bool Optimize )
2013-08-09 06:57:18 +02:00
{
2016-08-22 03:11:32 +02:00
lcMeshPrimitiveType PrimitiveType = ( LineType = = 2 ) ? LC_MESH_TEXTURED_LINES : LC_MESH_TEXTURED_TRIANGLES ;
2018-01-28 04:45:06 +01:00
lcLibraryMeshSection * Section = AddSection ( MeshDataType , PrimitiveType , ColorCode , TextureMap . Texture ) ;
2013-08-09 06:57:18 +02:00
2015-02-23 01:50:37 +01:00
int QuadIndices [ 4 ] = { 0 , 1 , 2 , 3 } ;
2013-08-09 06:57:18 +02:00
int Indices [ 4 ] = { - 1 , - 1 , - 1 , - 1 } ;
2017-02-28 01:03:12 +01:00
if ( LineType = = 3 | | LineType = = 4 )
2013-08-09 06:57:18 +02:00
{
2017-02-28 01:03:12 +01:00
if ( LineType = = 4 )
TestQuad ( QuadIndices , Vertices ) ;
2013-08-09 06:57:18 +02:00
2017-03-01 00:20:34 +01:00
lcVector3 Normal = lcNormalize ( lcCross ( Vertices [ 1 ] - Vertices [ 0 ] , Vertices [ 2 ] - Vertices [ 0 ] ) ) ;
2016-05-29 04:46:34 +02:00
2017-02-28 01:03:12 +01:00
if ( ! WindingCCW )
Normal = - Normal ;
2013-08-09 06:57:18 +02:00
2018-01-28 04:45:06 +01:00
lcVector2 TexCoords [ 4 ] ;
for ( int IndexIdx = 0 ; IndexIdx < lcMin ( LineType , 4 ) ; IndexIdx + + )
{
const lcVector3 & Position = Vertices [ QuadIndices [ IndexIdx ] ] ;
TexCoords [ QuadIndices [ IndexIdx ] ] = lcCalculateTexCoord ( Position , & TextureMap ) ;
}
2018-02-14 01:16:22 +01:00
if ( TextureMap . Type = = lcLibraryTextureMapType : : CYLINDRICAL | | TextureMap . Type = = lcLibraryTextureMapType : : SPHERICAL )
2018-01-28 04:45:06 +01:00
{
auto CheckTexCoordsWrap = [ & TexCoords , & Vertices , & TextureMap ] ( int Index1 , int Index2 , int Index3 )
{
float u12 = fabsf ( TexCoords [ Index1 ] . x - TexCoords [ Index2 ] . x ) ;
float u13 = fabsf ( TexCoords [ Index1 ] . x - TexCoords [ Index3 ] . x ) ;
float u23 = fabsf ( TexCoords [ Index2 ] . x - TexCoords [ Index3 ] . x ) ;
if ( u12 < 0.5f & & u13 < 0.5f & & u23 < 0.5f )
return ;
2019-03-17 21:17:11 +01:00
const lcVector4 & Plane2 = ( TextureMap . Type = = lcLibraryTextureMapType : : CYLINDRICAL ) ? TextureMap . Params . Cylindrical . Plane2 : TextureMap . Params . Spherical . Plane2 ;
2018-01-28 04:45:06 +01:00
float Dot1 = fabsf ( lcDot ( Plane2 , lcVector4 ( Vertices [ Index1 ] , 1.0f ) ) ) ;
float Dot2 = fabsf ( lcDot ( Plane2 , lcVector4 ( Vertices [ Index2 ] , 1.0f ) ) ) ;
float Dot3 = fabsf ( lcDot ( Plane2 , lcVector4 ( Vertices [ Index3 ] , 1.0f ) ) ) ;
if ( Dot1 > Dot2 )
{
if ( Dot1 > Dot3 )
{
if ( u12 > 0.5f )
TexCoords [ Index2 ] . x + = TexCoords [ Index2 ] . x < 0.5f ? 1.0f : - 1.0f ;
if ( u13 > 0.5f )
TexCoords [ Index3 ] . x + = TexCoords [ Index3 ] . x < 0.5f ? 1.0f : - 1.0f ;
}
else
{
if ( u13 > 0.5f )
TexCoords [ Index1 ] . x + = TexCoords [ Index1 ] . x < 0.5f ? 1.0f : - 1.0f ;
if ( u23 > 0.5f )
TexCoords [ Index2 ] . x + = TexCoords [ Index2 ] . x < 0.5f ? 1.0f : - 1.0f ;
}
}
else
{
if ( Dot2 > Dot3 )
{
if ( u12 > 0.5f )
TexCoords [ Index1 ] . x + = TexCoords [ Index1 ] . x < 0.5f ? 1.0f : - 1.0f ;
if ( u23 > 0.5f )
TexCoords [ Index3 ] . x + = TexCoords [ Index3 ] . x < 0.5f ? 1.0f : - 1.0f ;
}
else
{
if ( u13 > 0.5f )
TexCoords [ Index1 ] . x + = TexCoords [ Index1 ] . x < 0.5f ? 1.0f : - 1.0f ;
if ( u23 > 0.5f )
TexCoords [ Index2 ] . x + = TexCoords [ Index2 ] . x < 0.5f ? 1.0f : - 1.0f ;
}
}
} ;
CheckTexCoordsWrap ( QuadIndices [ 0 ] , QuadIndices [ 1 ] , QuadIndices [ 2 ] ) ;
if ( LineType = = 4 )
CheckTexCoordsWrap ( QuadIndices [ 2 ] , QuadIndices [ 3 ] , QuadIndices [ 0 ] ) ;
2018-02-14 01:16:22 +01:00
}
2018-01-28 19:03:59 +01:00
2018-02-14 01:16:22 +01:00
if ( TextureMap . Type = = lcLibraryTextureMapType : : SPHERICAL )
{
2018-01-28 19:03:59 +01:00
auto CheckTexCoordsPole = [ & TexCoords , & Vertices , & TextureMap ] ( int Index1 , int Index2 , int Index3 )
{
2019-03-17 21:17:11 +01:00
const lcVector4 & FrontPlane = TextureMap . Params . Spherical . FrontPlane ;
const lcVector4 & Plane2 = TextureMap . Params . Spherical . Plane2 ;
2018-01-28 19:03:59 +01:00
int PoleIndex ;
int EdgeIndex1 , EdgeIndex2 ;
if ( fabsf ( lcDot ( lcVector4 ( Vertices [ Index1 ] , 1.0f ) , FrontPlane ) ) < 0.01f & & fabsf ( lcDot ( lcVector4 ( Vertices [ Index1 ] , 1.0f ) , Plane2 ) ) < 0.01f )
{
PoleIndex = Index1 ;
EdgeIndex1 = Index2 ;
EdgeIndex2 = Index3 ;
}
else if ( fabsf ( lcDot ( lcVector4 ( Vertices [ Index2 ] , 1.0f ) , FrontPlane ) ) < 0.01f & & fabsf ( lcDot ( lcVector4 ( Vertices [ Index2 ] , 1.0f ) , Plane2 ) ) < 0.01f )
{
PoleIndex = Index2 ;
EdgeIndex1 = Index1 ;
EdgeIndex2 = Index3 ;
}
else if ( fabsf ( lcDot ( lcVector4 ( Vertices [ Index3 ] , 1.0f ) , FrontPlane ) ) < 0.01f & & fabsf ( lcDot ( lcVector4 ( Vertices [ Index3 ] , 1.0f ) , Plane2 ) ) < 0.01f )
{
PoleIndex = Index3 ;
EdgeIndex1 = Index1 ;
EdgeIndex2 = Index2 ;
}
else
return ;
lcVector3 OppositeEdge = Vertices [ EdgeIndex2 ] - Vertices [ EdgeIndex1 ] ;
lcVector3 SideEdge = Vertices [ PoleIndex ] - Vertices [ EdgeIndex1 ] ;
float OppositeLength = lcLength ( OppositeEdge ) ;
float Projection = lcDot ( OppositeEdge , SideEdge ) / ( OppositeLength * OppositeLength ) ;
TexCoords [ PoleIndex ] . x = TexCoords [ EdgeIndex1 ] . x + ( TexCoords [ EdgeIndex2 ] . x - TexCoords [ EdgeIndex1 ] . x ) * Projection ;
} ;
CheckTexCoordsPole ( QuadIndices [ 0 ] , QuadIndices [ 1 ] , QuadIndices [ 2 ] ) ;
if ( LineType = = 4 )
CheckTexCoordsPole ( QuadIndices [ 2 ] , QuadIndices [ 3 ] , QuadIndices [ 0 ] ) ;
2018-01-28 04:45:06 +01:00
}
2017-02-28 01:03:12 +01:00
for ( int IndexIdx = 0 ; IndexIdx < lcMin ( LineType , 4 ) ; IndexIdx + + )
{
const lcVector3 & Position = Vertices [ QuadIndices [ IndexIdx ] ] ;
2018-01-28 04:45:06 +01:00
Indices [ IndexIdx ] = AddTexturedVertex ( MeshDataType , Position , Normal , TexCoords [ QuadIndices [ IndexIdx ] ] , Optimize ) ;
2017-02-28 01:03:12 +01:00
}
}
else
{
for ( int IndexIdx = 0 ; IndexIdx < lcMin ( LineType , 4 ) ; IndexIdx + + )
2013-08-09 06:57:18 +02:00
{
2017-02-28 01:03:12 +01:00
const lcVector3 & Position = Vertices [ QuadIndices [ IndexIdx ] ] ;
2018-01-28 04:45:06 +01:00
lcVector2 TexCoord = lcCalculateTexCoord ( Position , & TextureMap ) ;
2017-02-28 01:03:12 +01:00
Indices [ IndexIdx ] = AddTexturedVertex ( MeshDataType , Position , TexCoord , Optimize ) ;
2013-08-09 06:57:18 +02:00
}
}
switch ( LineType )
{
case 4 :
if ( Indices [ 0 ] ! = Indices [ 2 ] & & Indices [ 0 ] ! = Indices [ 3 ] & & Indices [ 2 ] ! = Indices [ 3 ] )
{
2017-02-21 17:09:13 +01:00
if ( WindingCCW )
{
Section - > mIndices . Add ( Indices [ 2 ] ) ;
Section - > mIndices . Add ( Indices [ 3 ] ) ;
Section - > mIndices . Add ( Indices [ 0 ] ) ;
}
else
{
Section - > mIndices . Add ( Indices [ 0 ] ) ;
Section - > mIndices . Add ( Indices [ 3 ] ) ;
Section - > mIndices . Add ( Indices [ 2 ] ) ;
}
2013-08-09 06:57:18 +02:00
}
2018-09-24 20:29:05 +02:00
Q_FALLTHROUGH ( ) ;
2013-08-09 06:57:18 +02:00
case 3 :
if ( Indices [ 0 ] ! = Indices [ 1 ] & & Indices [ 0 ] ! = Indices [ 2 ] & & Indices [ 1 ] ! = Indices [ 2 ] )
{
2017-02-21 17:09:13 +01:00
if ( WindingCCW )
{
Section - > mIndices . Add ( Indices [ 0 ] ) ;
Section - > mIndices . Add ( Indices [ 1 ] ) ;
Section - > mIndices . Add ( Indices [ 2 ] ) ;
}
else
{
Section - > mIndices . Add ( Indices [ 2 ] ) ;
Section - > mIndices . Add ( Indices [ 1 ] ) ;
Section - > mIndices . Add ( Indices [ 0 ] ) ;
}
2013-08-09 06:57:18 +02:00
}
break ;
case 2 :
if ( Indices [ 0 ] ! = Indices [ 1 ] )
{
Section - > mIndices . Add ( Indices [ 0 ] ) ;
Section - > mIndices . Add ( Indices [ 1 ] ) ;
}
break ;
}
}
2017-12-02 21:22:04 +01:00
void lcLibraryMeshData : : AddMeshData ( const lcLibraryMeshData & Data , const lcMatrix44 & Transform , quint32 CurrentColorCode , bool InvertWinding , bool InvertNormals , lcLibraryTextureMap * TextureMap , lcMeshDataType OverrideDestIndex )
2013-08-09 06:57:18 +02:00
{
2015-05-24 06:36:25 +02:00
for ( int MeshDataIdx = 0 ; MeshDataIdx < LC_NUM_MESHDATA_TYPES ; MeshDataIdx + + )
2013-08-09 06:57:18 +02:00
{
2015-05-24 06:36:25 +02:00
int DestIndex = OverrideDestIndex = = LC_MESHDATA_SHARED ? MeshDataIdx : OverrideDestIndex ;
2017-02-28 01:03:12 +01:00
const lcArray < lcLibraryMeshVertex > & DataVertices = Data . mVertices [ MeshDataIdx ] ;
lcArray < lcLibraryMeshVertex > & Vertices = mVertices [ DestIndex ] ;
2013-08-09 06:57:18 +02:00
2015-05-24 06:36:25 +02:00
int VertexCount = DataVertices . GetSize ( ) ;
2017-12-02 21:22:04 +01:00
lcArray < quint32 > IndexRemap ( VertexCount ) ;
2015-05-24 06:36:25 +02:00
if ( ! TextureMap )
2013-08-09 06:57:18 +02:00
{
2015-05-24 06:36:25 +02:00
Vertices . AllocGrow ( VertexCount ) ;
2013-08-09 06:57:18 +02:00
2015-05-24 06:36:25 +02:00
for ( int SrcVertexIdx = 0 ; SrcVertexIdx < VertexCount ; SrcVertexIdx + + )
2013-08-09 06:57:18 +02:00
{
2015-05-24 06:36:25 +02:00
lcVector3 Position = lcMul31 ( DataVertices [ SrcVertexIdx ] . Position , Transform ) ;
2017-02-28 01:03:12 +01:00
int Index ;
2013-08-09 06:57:18 +02:00
2019-05-28 01:07:20 +02:00
if ( ( DataVertices [ SrcVertexIdx ] . Usage & LC_LIBRARY_VERTEX_TEXTURED ) = = 0 )
{
if ( DataVertices [ SrcVertexIdx ] . NormalWeight = = 0.0f )
Index = AddVertex ( ( lcMeshDataType ) DestIndex , Position , true ) ;
else
{
lcVector3 Normal = lcNormalize ( lcMul30 ( DataVertices [ SrcVertexIdx ] . Normal , Transform ) ) ;
if ( InvertNormals )
Normal = - Normal ;
Index = AddVertex ( ( lcMeshDataType ) DestIndex , Position , Normal , true ) ;
}
}
2017-02-28 01:03:12 +01:00
else
2015-05-24 06:36:25 +02:00
{
2019-05-28 01:07:20 +02:00
mHasTextures = true ;
if ( DataVertices [ SrcVertexIdx ] . NormalWeight = = 0.0f )
Index = AddTexturedVertex ( ( lcMeshDataType ) DestIndex , Position , DataVertices [ SrcVertexIdx ] . TexCoord , true ) ;
else
{
lcVector3 Normal = lcNormalize ( lcMul30 ( DataVertices [ SrcVertexIdx ] . Normal , Transform ) ) ;
if ( InvertNormals )
Normal = - Normal ;
Index = AddTexturedVertex ( ( lcMeshDataType ) DestIndex , Position , Normal , DataVertices [ SrcVertexIdx ] . TexCoord , true ) ;
}
Vertices [ Index ] . Usage = DataVertices [ SrcVertexIdx ] . Usage ;
2015-05-24 06:36:25 +02:00
}
2013-08-09 06:57:18 +02:00
2015-05-24 06:36:25 +02:00
IndexRemap . Add ( Index ) ;
}
2013-08-09 06:57:18 +02:00
}
2015-05-24 06:36:25 +02:00
else
2013-08-09 06:57:18 +02:00
{
2019-05-28 01:07:20 +02:00
mHasTextures = true ;
2013-08-09 06:57:18 +02:00
2015-05-24 06:36:25 +02:00
for ( int SrcVertexIdx = 0 ; SrcVertexIdx < VertexCount ; SrcVertexIdx + + )
2013-08-09 06:57:18 +02:00
{
2017-02-28 01:03:12 +01:00
const lcLibraryMeshVertex & SrcVertex = DataVertices [ SrcVertexIdx ] ;
2015-05-24 06:36:25 +02:00
lcVector3 Position = lcMul31 ( SrcVertex . Position , Transform ) ;
2018-01-18 00:14:24 +01:00
lcVector2 TexCoord = lcCalculateTexCoord ( Position , TextureMap ) ;
2017-02-28 01:03:12 +01:00
int Index ;
2013-08-09 06:57:18 +02:00
2017-02-28 01:03:12 +01:00
if ( DataVertices [ SrcVertexIdx ] . NormalWeight = = 0.0f )
2017-03-01 02:14:29 +01:00
Index = AddTexturedVertex ( ( lcMeshDataType ) DestIndex , Position , TexCoord , true ) ;
2017-02-28 01:03:12 +01:00
else
2015-05-24 06:36:25 +02:00
{
2017-03-01 00:20:34 +01:00
lcVector3 Normal = lcNormalize ( lcMul30 ( DataVertices [ SrcVertexIdx ] . Normal , Transform ) ) ;
2017-03-01 17:36:46 +01:00
if ( InvertNormals )
Normal = - Normal ;
2017-03-01 02:14:29 +01:00
Index = AddTexturedVertex ( ( lcMeshDataType ) DestIndex , Position , Normal , TexCoord , true ) ;
2015-05-24 06:36:25 +02:00
}
2013-08-09 06:57:18 +02:00
2019-05-28 01:07:20 +02:00
IndexRemap . Add ( Index ) ;
2015-05-24 06:36:25 +02:00
}
2013-08-09 06:57:18 +02:00
}
2015-05-24 06:36:25 +02:00
const lcArray < lcLibraryMeshSection * > & DataSections = Data . mSections [ MeshDataIdx ] ;
lcArray < lcLibraryMeshSection * > & Sections = mSections [ DestIndex ] ;
2013-08-09 06:57:18 +02:00
2015-05-24 06:36:25 +02:00
for ( int SrcSectionIdx = 0 ; SrcSectionIdx < DataSections . GetSize ( ) ; SrcSectionIdx + + )
2013-08-09 06:57:18 +02:00
{
2015-05-24 06:36:25 +02:00
lcLibraryMeshSection * SrcSection = DataSections [ SrcSectionIdx ] ;
2017-04-14 02:26:40 +02:00
lcLibraryMeshSection * DstSection = nullptr ;
2017-12-02 21:22:04 +01:00
quint32 ColorCode = SrcSection - > mColor = = 16 ? CurrentColorCode : SrcSection - > mColor ;
2015-05-24 06:36:25 +02:00
lcTexture * Texture ;
2018-01-13 06:23:43 +01:00
lcMeshPrimitiveType PrimitiveType = SrcSection - > mPrimitiveType ;
2015-05-24 06:36:25 +02:00
if ( SrcSection - > mTexture )
Texture = SrcSection - > mTexture ;
else if ( TextureMap )
2018-01-13 06:23:43 +01:00
{
2015-05-24 06:36:25 +02:00
Texture = TextureMap - > Texture ;
2018-01-13 06:23:43 +01:00
if ( SrcSection - > mPrimitiveType = = LC_MESH_TRIANGLES )
PrimitiveType = LC_MESH_TEXTURED_TRIANGLES ;
else if ( SrcSection - > mPrimitiveType = = LC_MESH_LINES )
PrimitiveType = LC_MESH_TEXTURED_LINES ;
}
2015-05-24 06:36:25 +02:00
else
2017-04-14 02:26:40 +02:00
Texture = nullptr ;
2013-08-09 06:57:18 +02:00
2015-05-24 06:36:25 +02:00
for ( int DstSectionIdx = 0 ; DstSectionIdx < Sections . GetSize ( ) ; DstSectionIdx + + )
2013-08-09 06:57:18 +02:00
{
2015-05-24 06:36:25 +02:00
lcLibraryMeshSection * Section = Sections [ DstSectionIdx ] ;
2018-01-13 06:23:43 +01:00
if ( Section - > mColor = = ColorCode & & Section - > mPrimitiveType = = PrimitiveType & & Section - > mTexture = = Texture )
2015-05-24 06:36:25 +02:00
{
DstSection = Section ;
break ;
}
2013-08-09 06:57:18 +02:00
}
2015-05-24 06:36:25 +02:00
if ( ! DstSection )
{
2018-01-13 06:23:43 +01:00
DstSection = new lcLibraryMeshSection ( PrimitiveType , ColorCode , Texture ) ;
2013-08-09 06:57:18 +02:00
2015-05-24 06:36:25 +02:00
Sections . Add ( DstSection ) ;
}
2013-08-09 06:57:18 +02:00
2015-05-24 06:36:25 +02:00
DstSection - > mIndices . AllocGrow ( SrcSection - > mIndices . GetSize ( ) ) ;
2013-08-09 06:57:18 +02:00
2019-05-28 01:07:20 +02:00
if ( ! InvertWinding | | ( PrimitiveType ! = LC_MESH_TRIANGLES & & PrimitiveType ! = LC_MESH_TEXTURED_TRIANGLES ) )
2015-05-24 06:36:25 +02:00
{
2019-05-28 01:07:20 +02:00
for ( int IndexIdx = 0 ; IndexIdx < SrcSection - > mIndices . GetSize ( ) ; IndexIdx + + )
DstSection - > mIndices . Add ( IndexRemap [ SrcSection - > mIndices [ IndexIdx ] ] ) ;
2015-05-24 06:36:25 +02:00
}
else
{
2019-05-28 01:07:20 +02:00
for ( int IndexIdx = 0 ; IndexIdx < SrcSection - > mIndices . GetSize ( ) ; IndexIdx + = 3 )
2017-02-21 17:09:13 +01:00
{
2019-05-28 01:07:20 +02:00
DstSection - > mIndices . Add ( IndexRemap [ SrcSection - > mIndices [ IndexIdx + 2 ] ] ) ;
DstSection - > mIndices . Add ( IndexRemap [ SrcSection - > mIndices [ IndexIdx + 1 ] ] ) ;
DstSection - > mIndices . Add ( IndexRemap [ SrcSection - > mIndices [ IndexIdx + 0 ] ] ) ;
2017-02-21 17:09:13 +01:00
}
2015-05-24 06:36:25 +02:00
}
2013-08-09 06:57:18 +02:00
}
}
}
2017-12-02 21:22:04 +01:00
void lcLibraryMeshData : : AddMeshDataNoDuplicateCheck ( const lcLibraryMeshData & Data , const lcMatrix44 & Transform , quint32 CurrentColorCode , bool InvertWinding , bool InvertNormals , lcLibraryTextureMap * TextureMap , lcMeshDataType OverrideDestIndex )
2013-08-09 06:57:18 +02:00
{
2015-05-24 06:36:25 +02:00
for ( int MeshDataIdx = 0 ; MeshDataIdx < LC_NUM_MESHDATA_TYPES ; MeshDataIdx + + )
2013-08-09 06:57:18 +02:00
{
2015-05-24 06:36:25 +02:00
int DestIndex = OverrideDestIndex = = LC_MESHDATA_SHARED ? MeshDataIdx : OverrideDestIndex ;
2017-02-28 01:03:12 +01:00
const lcArray < lcLibraryMeshVertex > & DataVertices = Data . mVertices [ MeshDataIdx ] ;
lcArray < lcLibraryMeshVertex > & Vertices = mVertices [ DestIndex ] ;
2017-12-02 21:22:04 +01:00
quint32 BaseIndex ;
2013-08-09 06:57:18 +02:00
2015-05-24 06:36:25 +02:00
if ( ! TextureMap )
2013-08-09 06:57:18 +02:00
{
2015-05-24 06:36:25 +02:00
BaseIndex = Vertices . GetSize ( ) ;
2013-08-09 06:57:18 +02:00
2016-05-29 04:46:34 +02:00
Vertices . SetGrow ( lcMin ( Vertices . GetSize ( ) , 8 * 1024 * 1024 ) ) ;
2015-05-24 06:36:25 +02:00
Vertices . AllocGrow ( DataVertices . GetSize ( ) ) ;
2013-08-09 06:57:18 +02:00
2015-05-24 06:36:25 +02:00
for ( int SrcVertexIdx = 0 ; SrcVertexIdx < DataVertices . GetSize ( ) ; SrcVertexIdx + + )
{
2017-02-28 01:03:12 +01:00
const lcLibraryMeshVertex & SrcVertex = DataVertices [ SrcVertexIdx ] ;
lcLibraryMeshVertex & DstVertex = Vertices . Add ( ) ;
DstVertex . Position = lcMul31 ( SrcVertex . Position , Transform ) ;
2017-03-01 00:20:34 +01:00
DstVertex . Normal = lcNormalize ( lcMul30 ( SrcVertex . Normal , Transform ) ) ;
2017-03-01 17:36:46 +01:00
if ( InvertNormals )
DstVertex . Normal = - DstVertex . Normal ;
2017-02-28 01:03:12 +01:00
DstVertex . NormalWeight = SrcVertex . NormalWeight ;
2019-05-28 01:07:20 +02:00
DstVertex . TexCoord = SrcVertex . TexCoord ;
DstVertex . Usage = SrcVertex . Usage ;
2015-05-24 06:36:25 +02:00
}
}
else
2013-08-09 06:57:18 +02:00
{
2019-05-28 01:07:20 +02:00
mHasTextures = true ;
BaseIndex = Vertices . GetSize ( ) ;
2013-08-09 06:57:18 +02:00
2019-05-28 01:07:20 +02:00
Vertices . AllocGrow ( DataVertices . GetSize ( ) ) ;
2013-08-09 06:57:18 +02:00
2015-05-24 06:36:25 +02:00
for ( int SrcVertexIdx = 0 ; SrcVertexIdx < DataVertices . GetSize ( ) ; SrcVertexIdx + + )
{
2017-02-28 01:03:12 +01:00
const lcLibraryMeshVertex & SrcVertex = DataVertices [ SrcVertexIdx ] ;
2019-05-28 01:07:20 +02:00
lcLibraryMeshVertex & DstVertex = Vertices . Add ( ) ;
2015-05-24 06:36:25 +02:00
lcVector3 Position = lcMul31 ( SrcVertex . Position , Transform ) ;
2018-01-18 00:14:24 +01:00
lcVector2 TexCoord = lcCalculateTexCoord ( Position , TextureMap ) ;
2015-05-24 06:36:25 +02:00
DstVertex . Position = Position ;
2017-03-01 00:20:34 +01:00
DstVertex . Normal = lcNormalize ( lcMul30 ( SrcVertex . Normal , Transform ) ) ;
2017-03-01 17:36:46 +01:00
if ( InvertNormals )
DstVertex . Normal = - DstVertex . Normal ;
2017-02-28 01:03:12 +01:00
DstVertex . NormalWeight = SrcVertex . NormalWeight ;
2015-05-24 06:36:25 +02:00
DstVertex . TexCoord = TexCoord ;
2019-05-28 01:07:20 +02:00
DstVertex . Usage = LC_LIBRARY_VERTEX_TEXTURED ;
2015-05-24 06:36:25 +02:00
}
2013-08-09 06:57:18 +02:00
}
2015-05-24 06:36:25 +02:00
const lcArray < lcLibraryMeshSection * > & DataSections = Data . mSections [ MeshDataIdx ] ;
lcArray < lcLibraryMeshSection * > & Sections = mSections [ DestIndex ] ;
2013-08-09 06:57:18 +02:00
2015-05-24 06:36:25 +02:00
for ( int SrcSectionIdx = 0 ; SrcSectionIdx < DataSections . GetSize ( ) ; SrcSectionIdx + + )
2013-08-09 06:57:18 +02:00
{
2015-05-24 06:36:25 +02:00
lcLibraryMeshSection * SrcSection = DataSections [ SrcSectionIdx ] ;
2017-04-14 02:26:40 +02:00
lcLibraryMeshSection * DstSection = nullptr ;
2017-12-02 21:22:04 +01:00
quint32 ColorCode = SrcSection - > mColor = = 16 ? CurrentColorCode : SrcSection - > mColor ;
2015-05-24 06:36:25 +02:00
lcTexture * Texture ;
if ( SrcSection - > mTexture )
Texture = SrcSection - > mTexture ;
else if ( TextureMap )
Texture = TextureMap - > Texture ;
else
2017-04-14 02:26:40 +02:00
Texture = nullptr ;
2013-08-09 06:57:18 +02:00
2015-05-24 06:36:25 +02:00
for ( int DstSectionIdx = 0 ; DstSectionIdx < Sections . GetSize ( ) ; DstSectionIdx + + )
2013-08-09 06:57:18 +02:00
{
2015-05-24 06:36:25 +02:00
lcLibraryMeshSection * Section = Sections [ DstSectionIdx ] ;
if ( Section - > mColor = = ColorCode & & Section - > mPrimitiveType = = SrcSection - > mPrimitiveType & & Section - > mTexture = = Texture )
{
DstSection = Section ;
break ;
}
2013-08-09 06:57:18 +02:00
}
2015-05-24 06:36:25 +02:00
if ( ! DstSection )
{
DstSection = new lcLibraryMeshSection ( SrcSection - > mPrimitiveType , ColorCode , Texture ) ;
2013-08-09 06:57:18 +02:00
2015-05-24 06:36:25 +02:00
Sections . Add ( DstSection ) ;
}
2013-08-09 06:57:18 +02:00
2016-05-29 18:42:47 +02:00
DstSection - > mIndices . SetGrow ( lcMin ( DstSection - > mIndices . GetSize ( ) , 8 * 1024 * 1024 ) ) ;
2015-05-24 06:36:25 +02:00
DstSection - > mIndices . AllocGrow ( SrcSection - > mIndices . GetSize ( ) ) ;
2013-08-09 06:57:18 +02:00
2019-05-28 01:07:20 +02:00
if ( ! InvertWinding | | ( SrcSection - > mPrimitiveType ! = LC_MESH_TRIANGLES & & SrcSection - > mPrimitiveType ! = LC_MESH_TEXTURED_TRIANGLES ) )
2015-05-24 06:36:25 +02:00
{
2019-05-28 01:07:20 +02:00
for ( int IndexIdx = 0 ; IndexIdx < SrcSection - > mIndices . GetSize ( ) ; IndexIdx + + )
DstSection - > mIndices . Add ( BaseIndex + SrcSection - > mIndices [ IndexIdx ] ) ;
2015-05-24 06:36:25 +02:00
}
else
{
2019-05-28 01:07:20 +02:00
for ( int IndexIdx = 0 ; IndexIdx < SrcSection - > mIndices . GetSize ( ) ; IndexIdx + = 3 )
2017-02-21 17:09:13 +01:00
{
2019-05-28 01:07:20 +02:00
DstSection - > mIndices . Add ( BaseIndex + SrcSection - > mIndices [ IndexIdx + 2 ] ) ;
DstSection - > mIndices . Add ( BaseIndex + SrcSection - > mIndices [ IndexIdx + 1 ] ) ;
DstSection - > mIndices . Add ( BaseIndex + SrcSection - > mIndices [ IndexIdx + 0 ] ) ;
2017-02-21 17:09:13 +01:00
}
2015-05-24 06:36:25 +02:00
}
2013-08-09 06:57:18 +02:00
}
}
}
2017-02-08 03:55:54 +01:00
bool lcPiecesLibrary : : PieceInCategory ( PieceInfo * Info , const char * CategoryKeywords ) const
2013-08-09 06:57:18 +02:00
{
2015-02-22 03:39:15 +01:00
if ( Info - > IsTemporary ( ) )
return false ;
2017-02-08 03:55:54 +01:00
const char * PieceName ;
2013-08-09 06:57:18 +02:00
if ( Info - > m_strDescription [ 0 ] = = ' ~ ' | | Info - > m_strDescription [ 0 ] = = ' _ ' )
PieceName = Info - > m_strDescription + 1 ;
else
PieceName = Info - > m_strDescription ;
2017-02-08 03:55:54 +01:00
return lcMatchCategory ( PieceName , CategoryKeywords ) ;
2013-08-09 06:57:18 +02:00
}
2013-08-16 01:43:18 +02:00
void lcPiecesLibrary : : GetCategoryEntries ( int CategoryIndex , bool GroupPieces , lcArray < PieceInfo * > & SinglePieces , lcArray < PieceInfo * > & GroupedPieces )
2013-08-09 06:57:18 +02:00
{
2016-12-16 18:14:19 +01:00
if ( CategoryIndex > = 0 & & CategoryIndex < gCategories . GetSize ( ) )
2017-02-08 18:41:48 +01:00
GetCategoryEntries ( gCategories [ CategoryIndex ] . Keywords . constData ( ) , GroupPieces , SinglePieces , GroupedPieces ) ;
2013-08-09 06:57:18 +02:00
}
2017-02-08 03:55:54 +01:00
void lcPiecesLibrary : : GetCategoryEntries ( const char * CategoryKeywords , bool GroupPieces , lcArray < PieceInfo * > & SinglePieces , lcArray < PieceInfo * > & GroupedPieces )
2013-08-09 06:57:18 +02:00
{
SinglePieces . RemoveAll ( ) ;
GroupedPieces . RemoveAll ( ) ;
2018-02-22 02:27:24 +01:00
for ( const auto & PieceIt : mPieces )
2013-08-09 06:57:18 +02:00
{
2017-07-24 04:35:18 +02:00
PieceInfo * Info = PieceIt . second ;
2013-08-09 06:57:18 +02:00
if ( ! PieceInCategory ( Info , CategoryKeywords ) )
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 ] ;
2017-07-27 18:21:55 +02:00
strcpy ( ParentName , Info - > mFileName ) ;
2013-08-09 06:57:18 +02:00
* strchr ( ParentName , ' P ' ) = ' \0 ' ;
2017-07-27 18:21:55 +02:00
strcat ( ParentName , " .dat " ) ;
2013-08-09 06:57:18 +02:00
2017-04-14 02:26:40 +02:00
Parent = FindPiece ( ParentName , nullptr , false , false ) ;
2013-08-09 06:57:18 +02:00
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 ) ;
}
}
}
2013-08-16 01:43:18 +02:00
void lcPiecesLibrary : : GetPatternedPieces ( PieceInfo * Parent , lcArray < PieceInfo * > & Pieces ) const
2013-08-09 06:57:18 +02:00
{
char Name [ LC_PIECE_NAME_LEN ] ;
2017-07-27 18:21:55 +02:00
strcpy ( Name , Parent - > mFileName ) ;
char * Ext = strchr ( Name , ' . ' ) ;
if ( Ext )
* Ext = 0 ;
2013-08-09 06:57:18 +02:00
strcat ( Name , " P " ) ;
2017-07-27 18:21:55 +02:00
strupr ( Name ) ;
2013-08-09 06:57:18 +02:00
Pieces . RemoveAll ( ) ;
2018-02-22 02:27:24 +01:00
for ( const auto & PieceIt : mPieces )
2017-07-27 18:21:55 +02:00
if ( strncmp ( Name , PieceIt . first . c_str ( ) , strlen ( Name ) ) = = 0 )
Pieces . Add ( PieceIt . second ) ;
2013-08-09 06:57:18 +02:00
// Sometimes pieces with A and B versions don't follow the same convention (for example, 3040Pxx instead of 3040BPxx).
if ( Pieces . GetSize ( ) = = 0 )
{
2017-07-27 18:21:55 +02:00
strcpy ( Name , Parent - > mFileName ) ;
Ext = strchr ( Name , ' . ' ) ;
if ( Ext )
* Ext = 0 ;
2016-02-17 00:11:52 +01:00
size_t Len = strlen ( Name ) ;
2013-08-09 06:57:18 +02:00
if ( Name [ Len - 1 ] < ' 0 ' | | Name [ Len - 1 ] > ' 9 ' )
Name [ Len - 1 ] = ' P ' ;
2018-02-22 02:27:24 +01:00
for ( const auto & PieceIt : mPieces )
2017-07-27 18:21:55 +02:00
if ( strncmp ( Name , PieceIt . first . c_str ( ) , strlen ( Name ) ) = = 0 )
Pieces . Add ( PieceIt . second ) ;
2013-08-09 06:57:18 +02:00
}
}
2017-02-01 06:12:30 +01:00
void lcPiecesLibrary : : GetParts ( lcArray < PieceInfo * > & Parts )
{
2017-07-24 04:35:18 +02:00
Parts . SetSize ( 0 ) ;
Parts . AllocGrow ( mPieces . size ( ) ) ;
2018-02-22 02:27:24 +01:00
for ( const auto & PartIt : mPieces )
2017-07-24 04:35:18 +02:00
Parts . Add ( PartIt . second ) ;
2017-02-01 06:12:30 +01:00
}
2014-09-11 21:55:34 +02:00
bool lcPiecesLibrary : : LoadBuiltinPieces ( )
2014-09-10 03:41:37 +02:00
{
2014-09-11 21:55:34 +02:00
QResource Resource ( " :/resources/library.zip " ) ;
2013-08-09 06:57:18 +02:00
2014-09-11 21:55:34 +02:00
if ( ! Resource . isValid ( ) )
return false ;
2013-08-09 06:57:18 +02:00
2014-09-11 21:55:34 +02:00
lcMemFile * File = new lcMemFile ( ) ;
File - > WriteBuffer ( Resource . data ( ) , Resource . size ( ) ) ;
2013-08-09 06:57:18 +02:00
2014-09-11 21:55:34 +02:00
if ( ! OpenArchive ( File , " builtin " , LC_ZIPFILE_OFFICIAL ) )
2014-09-10 03:41:37 +02:00
{
2014-09-11 21:55:34 +02:00
delete File ;
return false ;
2014-09-10 03:41:37 +02:00
}
2014-09-11 21:55:34 +02:00
lcMemFile PieceFile ;
2013-08-09 06:57:18 +02:00
2018-02-22 02:27:24 +01:00
for ( const auto & PieceIt : mPieces )
2014-09-10 03:41:37 +02:00
{
2017-07-24 04:35:18 +02:00
PieceInfo * Info = PieceIt . second ;
2014-09-10 03:41:37 +02:00
2014-09-11 21:55:34 +02:00
mZipFiles [ Info - > mZipFileType ] - > ExtractFile ( Info - > mZipFileIndex , PieceFile , 256 ) ;
PieceFile . Seek ( 0 , SEEK_END ) ;
PieceFile . WriteU8 ( 0 ) ;
2014-09-10 03:41:37 +02:00
2014-09-11 21:55:34 +02:00
char * Src = ( char * ) PieceFile . mBuffer + 2 ;
char * Dst = Info - > m_strDescription ;
2013-08-09 06:57:18 +02:00
2014-09-11 21:55:34 +02:00
for ( ; ; )
2013-08-09 06:57:18 +02:00
{
2014-09-11 21:55:34 +02:00
if ( * Src ! = ' \r ' & & * Src ! = ' \n ' & & * Src & & Dst - Info - > m_strDescription < ( int ) sizeof ( Info - > m_strDescription ) - 1 )
2014-08-30 21:48:36 +02:00
{
2014-09-11 21:55:34 +02:00
* Dst + + = * Src + + ;
continue ;
2013-08-09 06:57:18 +02:00
}
2014-09-11 21:55:34 +02:00
* Dst = 0 ;
break ;
2013-08-09 06:57:18 +02:00
}
}
2014-09-11 21:55:34 +02:00
lcLoadDefaultColors ( ) ;
lcLoadDefaultCategories ( true ) ;
2016-02-29 21:13:54 +01:00
lcSynthInit ( ) ;
2014-09-11 21:55:34 +02:00
return true ;
2013-08-09 06:57:18 +02:00
}