2016-03-19 06:57:51 +13:00
# include "toonz/txshsimplelevel.h"
# include "imagebuilders.h"
// TnzLib includes
# include "toonz/txshleveltypes.h"
# include "toonz/imagemanager.h"
# include "toonz/studiopalette.h"
# include "toonz/hook.h"
# include "toonz/toonzscene.h"
# include "toonz/levelproperties.h"
# include "toonz/levelupdater.h"
# include "toonz/fullcolorpalette.h"
# include "toonz/preferences.h"
# include "toonz/stage.h"
# include "toonz/textureutils.h"
# include "toonz/levelset.h"
// TnzBase includes
# include "tenv.h"
// TnzCore includes
# include "trasterimage.h"
# include "tvectorimage.h"
# include "tmeshimage.h"
# include "timagecache.h"
# include "tofflinegl.h"
# include "tvectorgl.h"
# include "tvectorrenderdata.h"
# include "tropcm.h"
# include "tpixelutils.h"
# include "timageinfo.h"
# include "tlogger.h"
# include "tstream.h"
# include "tsystem.h"
# include "tcontenthistory.h"
// Qt includes
# include <QDir>
# include <QRegExp>
# include <QMessageBox>
# include "../common/psdlib/psd.h"
namespace bc = boost : : container ;
//******************************************************************************************
// Global stuff
//******************************************************************************************
DEFINE_CLASS_CODE ( TXshSimpleLevel , 20 )
PERSIST_IDENTIFIER ( TXshSimpleLevel , " level " )
//******************************************************************************************
// Local namespace stuff
//******************************************************************************************
namespace
{
int idBaseCode = 1 ;
//-----------------------------------------------------------------------------
struct CompatibilityStruct {
int writeMask , neededMask , forbiddenMask ;
} ;
CompatibilityStruct compatibility =
{
0x00F1 , // mask written. Note: Student main must be 0x00F2
// Note: the 0x00F0 part is currently not used.
0x0000 , // mandatory mask: loaded levels MUST have a mask with these bits set
// Note: if mandatory mask != 0 then no old level (without mask)
// can be loaded
// Note: this mask is currently not used.
0x000E // forbidden mask: loaded levels MUST NOT have a mask with these bits set
//
} ;
//-----------------------------------------------------------------------------
inline std : : string rasterized ( std : : string id ) { return id + " _rasterized " ; }
inline std : : string filled ( std : : string id ) { return id + " _filled " ; }
//-----------------------------------------------------------------------------
QString getCreatorString ( )
{
QString creator =
QString : : fromStdString ( TEnv : : getApplicationName ( ) ) + " " +
QString : : fromStdString ( TEnv : : getApplicationVersion ( ) ) +
" CM( " + QString : : number ( compatibility . writeMask , 16 ) + " ) " ;
return creator ;
}
//-----------------------------------------------------------------------------
bool checkCreatorString ( const QString & creator )
{
int mask = 0 ;
if ( creator ! = " " ) {
QRegExp rx ( " CM \\ ([0-9A-Fa-f]* \\ ) " ) ;
int pos = rx . indexIn ( creator ) ;
int len = rx . matchedLength ( ) ;
if ( pos > = 0 & & len > = 4 ) {
QString v ;
if ( len > 4 )
v = creator . mid ( pos + 3 , len - 4 ) ;
bool ok = true ;
mask = v . toInt ( & ok , 16 ) ;
}
}
return ( mask & compatibility . neededMask ) = = compatibility . neededMask & &
( mask & compatibility . forbiddenMask ) = = 0 ;
}
//-----------------------------------------------------------------------------
bool isAreadOnlyLevel ( const TFilePath & path )
{
if ( path . isEmpty ( ) | | ! path . isAbsolute ( ) )
return false ;
if ( path . getDots ( ) = = " . " | | ( path . getDots ( ) = = " .. " & & ( path . getType ( ) = = " tlv " | | path . getType ( ) = = " tpl " ) ) ) {
if ( ! TSystem : : doesExistFileOrLevel ( path ) )
return false ;
TFileStatus fs ( path ) ;
return ! fs . isWritable ( ) ;
}
/*- 処理が重くなるので、連番ファイルは全てfalseを返す -*/
/*
else if ( path . getDots ( ) = = " .. " )
{
TFilePath dir = path . getParentDir ( ) ;
QDir qDir ( QString : : fromStdWString ( dir . getWideString ( ) ) ) ;
QString levelName = QRegExp : : escape ( QString : : fromStdWString ( path . getWideName ( ) ) ) ;
QString levelType = QString : : fromStdString ( path . getType ( ) ) ;
QString exp ( levelName + " .[0-9]{1,4}. " + levelType ) ;
QRegExp regExp ( exp ) ;
QStringList list = qDir . entryList ( QDir : : Files ) ;
QStringList livelFrames = list . filter ( regExp ) ;
bool isReadOnly = false ;
int i ;
for ( i = 0 ; i < livelFrames . size ( ) & & ! isReadOnly ; i + + )
{
TFilePath frame = dir + TFilePath ( livelFrames [ i ] . toStdWString ( ) ) ;
if ( frame . isEmpty ( ) | | ! frame . isAbsolute ( ) ) continue ;
TFileStatus fs ( frame ) ;
isReadOnly = ! fs . isWritable ( ) ;
}
return isReadOnly ;
}
*/
else
return false ;
}
//-----------------------------------------------------------------------------
void getIndexesRangefromFids (
TXshSimpleLevel * level , const std : : set < TFrameId > & fids , int & fromIndex , int & toIndex )
{
if ( fids . empty ( ) ) {
fromIndex = toIndex = - 1 ;
return ;
}
toIndex = 0 ;
fromIndex = level - > getFrameCount ( ) - 1 ;
std : : set < TFrameId > : : const_iterator it ;
for ( it = fids . begin ( ) ; it ! = fids . end ( ) ; + + it ) {
int index = level - > guessIndex ( * it ) ;
if ( index > toIndex )
toIndex = index ;
if ( index < fromIndex )
fromIndex = index ;
}
}
} // namespace
//******************************************************************************************
// TXshSimpleLevel impementation
//******************************************************************************************
bool TXshSimpleLevel : : m_rasterizePli = false ;
bool TXshSimpleLevel : : m_fillFullColorRaster = false ;
//-----------------------------------------------------------------------------
2016-04-19 19:32:17 +12:00
TXshSimpleLevel : : TXshSimpleLevel ( const std : : wstring & name )
2016-03-19 06:57:51 +13:00
: TXshLevel ( m_classCode , name ) , m_properties ( new LevelProperties ) , m_palette ( 0 ) , m_idBase ( toString ( idBaseCode + + ) ) , m_editableRangeUserInfo ( L " " ) , m_isSubsequence ( false ) , m_16BitChannelLevel ( false ) , m_isReadOnly ( false ) , m_temporaryHookMerged ( false )
{
}
//-----------------------------------------------------------------------------
TXshSimpleLevel : : ~ TXshSimpleLevel ( )
{
clearFrames ( ) ;
if ( m_palette )
m_palette - > release ( ) ;
}
//-----------------------------------------------------------------------------
2016-04-19 19:32:17 +12:00
void TXshSimpleLevel : : setEditableRange ( unsigned int from , unsigned int to , const std : : wstring & userName )
2016-03-19 06:57:51 +13:00
{
assert ( from < = to & & to < ( unsigned int ) getFrameCount ( ) ) ;
unsigned int i ;
for ( i = from ; i < = to ; i + + )
m_editableRange . insert ( index2fid ( i ) ) ;
QString hostName = TSystem : : getHostName ( ) ;
m_editableRangeUserInfo = userName + L " _ " + hostName . toStdWString ( ) ;
2016-04-19 19:32:17 +12:00
std : : wstring fileName = getEditableFileName ( ) ;
2016-03-19 06:57:51 +13:00
TFilePath dstPath = getScene ( ) - > decodeFilePath ( m_path ) ;
dstPath = dstPath . withName ( fileName ) . withType ( dstPath . getType ( ) ) ;
// Load temporary level file (for pli and tlv types only)
if ( getType ( ) ! = OVL_XSHLEVEL & & TSystem : : doesExistFileOrLevel ( dstPath ) ) {
TLevelReaderP lr ( dstPath ) ;
TLevelP level = lr - > loadInfo ( ) ;
setPalette ( level - > getPalette ( ) ) ;
for ( TLevel : : Iterator it = level - > begin ( ) ; it ! = level - > end ( ) ; it + + ) {
TImageP img = lr - > getFrameReader ( it - > first ) - > load ( ) ;
setFrame ( it - > first , img ) ;
}
}
// Merge temporary hook file with current hookset
const TFilePath & hookFile = getHookPath ( dstPath ) ;
mergeTemporaryHookFile ( from , to , hookFile ) ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : mergeTemporaryHookFile ( unsigned int from , unsigned int to , const TFilePath & hookFile )
{
if ( ! TFileStatus ( hookFile ) . doesExist ( ) )
return ;
HookSet * tempHookSet = new HookSet ;
TIStream is ( hookFile ) ;
2016-04-19 19:32:17 +12:00
std : : string tagName ;
2016-03-19 06:57:51 +13:00
try {
if ( is . matchTag ( tagName ) & & tagName = = " hooks " )
tempHookSet - > loadData ( is ) ;
} catch ( . . . ) {
}
HookSet * hookSet = getHookSet ( ) ;
int tempHookCount = tempHookSet - > getHookCount ( ) ;
if ( tempHookCount = = 0 ) {
for ( unsigned int f = from ; f < = to ; f + + ) {
TFrameId fid = index2fid ( f ) ;
hookSet - > eraseFrame ( fid ) ;
}
} else {
for ( int i = 0 ; i < tempHookCount ; i + + ) {
Hook * hook = tempHookSet - > getHook ( i ) ;
Hook * newHook = hookSet - > touchHook ( hook - > getId ( ) ) ;
newHook - > setTrackerObjectId ( hook - > getTrackerObjectId ( ) ) ;
newHook - > setTrackerRegionHeight ( hook - > getTrackerRegionHeight ( ) ) ;
newHook - > setTrackerRegionWidth ( hook - > getTrackerRegionWidth ( ) ) ;
for ( unsigned int f = from ; f < = to ; f + + ) {
TFrameId fid = index2fid ( f ) ;
newHook - > setAPos ( fid , hook - > getAPos ( fid ) ) ;
newHook - > setBPos ( fid , hook - > getBPos ( fid ) ) ;
}
}
}
m_temporaryHookMerged = true ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : clearEditableRange ( )
{
m_editableRange . clear ( ) ;
m_editableRangeUserInfo = L " " ;
}
//-----------------------------------------------------------------------------
2016-04-19 19:32:17 +12:00
std : : wstring TXshSimpleLevel : : getEditableFileName ( )
2016-03-19 06:57:51 +13:00
{
# ifdef MACOSX
2016-04-19 19:32:17 +12:00
std : : wstring fileName = L " . " + m_path . getWideName ( ) ;
2016-03-19 06:57:51 +13:00
# else
2016-04-19 19:32:17 +12:00
std : : wstring fileName = m_path . getWideName ( ) ;
2016-03-19 06:57:51 +13:00
# endif
fileName + = L " _ " + m_editableRangeUserInfo ;
int from , to ;
getIndexesRangefromFids ( this , m_editableRange , from , to ) ;
if ( from = = - 1 & & to = = - 1 )
return L " " ;
fileName + = L " _ " + toWideString ( from + 1 ) + L " - " + toWideString ( to + 1 ) ;
return fileName ;
}
//-----------------------------------------------------------------------------
std : : set < TFrameId > TXshSimpleLevel : : getEditableRange ( )
{
return m_editableRange ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : setRenumberTable ( )
{
m_renumberTable . clear ( ) ;
FramesSet : : iterator ft , fEnd = m_frames . end ( ) ;
for ( ft = m_frames . begin ( ) ; ft ! = fEnd ; + + ft )
m_renumberTable [ * ft ] = * ft ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : setDirtyFlag ( bool on )
{
m_properties - > setDirtyFlag ( on ) ;
}
//-----------------------------------------------------------------------------
bool TXshSimpleLevel : : getDirtyFlag ( ) const
{
return m_properties - > getDirtyFlag ( ) ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : touchFrame ( const TFrameId & fid )
{
m_properties - > setDirtyFlag ( true ) ;
TContentHistory * ch = getContentHistory ( ) ;
if ( ! ch ) {
ch = new TContentHistory ( true ) ;
setContentHistory ( ch ) ;
}
ch - > frameModifiedNow ( fid ) ;
if ( getType ( ) = = PLI_XSHLEVEL ) {
2016-04-19 19:32:17 +12:00
std : : string id = rasterized ( getImageId ( fid ) ) ;
2016-03-19 06:57:51 +13:00
ImageManager : : instance ( ) - > invalidate ( id ) ;
}
if ( getType ( ) & FULLCOLOR_TYPE ) {
2016-04-19 19:32:17 +12:00
std : : string id = filled ( getImageId ( fid ) ) ;
2016-03-19 06:57:51 +13:00
ImageManager : : instance ( ) - > invalidate ( id ) ;
}
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : onPaletteChanged ( )
{
FramesSet : : iterator ft , fEnd = m_frames . end ( ) ;
for ( ft = m_frames . begin ( ) ; ft ! = fEnd ; + + ft ) {
const TFrameId & fid = * ft ;
if ( getType ( ) = = PLI_XSHLEVEL ) {
2016-04-19 19:32:17 +12:00
std : : string id = rasterized ( getImageId ( fid ) ) ;
2016-03-19 06:57:51 +13:00
ImageManager : : instance ( ) - > invalidate ( id ) ;
}
if ( getType ( ) & FULLCOLOR_TYPE ) {
2016-04-19 19:32:17 +12:00
std : : string id = filled ( getImageId ( fid ) ) ;
2016-03-19 06:57:51 +13:00
ImageManager : : instance ( ) - > invalidate ( id ) ;
}
texture_utils : : invalidateTexture ( this , fid ) ;
}
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : setScannedPath ( const TFilePath & fp )
{
m_scannedPath = fp ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : setPath ( const TFilePath & fp , bool keepFrames )
{
m_path = fp ;
if ( ! keepFrames ) {
clearFrames ( ) ;
assert ( getScene ( ) ) ;
try {
load ( ) ;
} catch ( . . . ) {
}
}
if ( getType ( ) ! = PLI_XSHLEVEL ) {
if ( ! m_frames . empty ( ) ) {
2016-04-19 19:32:17 +12:00
std : : string imageId = getImageId ( getFirstFid ( ) ) ;
2016-03-19 06:57:51 +13:00
const TImageInfo * imageInfo = ImageManager : : instance ( ) - > getInfo ( imageId , ImageManager : : none , 0 ) ;
if ( imageInfo ) {
TDimension imageRes ( 0 , 0 ) ;
TPointD imageDpi ;
imageRes . lx = imageInfo - > m_lx ;
imageRes . ly = imageInfo - > m_ly ;
imageDpi . x = imageInfo - > m_dpix ;
imageDpi . y = imageInfo - > m_dpiy ;
m_properties - > setImageDpi ( imageDpi ) ;
m_properties - > setImageRes ( imageRes ) ;
m_properties - > setBpp ( imageInfo - > m_bitsPerSample * imageInfo - > m_samplePerPixel ) ;
}
}
}
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : clonePropertiesFrom ( const TXshSimpleLevel * oldSl )
{
m_properties - > setImageDpi ( oldSl - > m_properties - > getImageDpi ( ) ) ; // Watch out - may change dpi policy!
m_properties - > setDpi ( oldSl - > m_properties - > getDpi ( ) ) ;
m_properties - > setDpiPolicy ( oldSl - > m_properties - > getDpiPolicy ( ) ) ;
m_properties - > setImageRes ( oldSl - > m_properties - > getImageRes ( ) ) ;
m_properties - > setBpp ( oldSl - > m_properties - > getBpp ( ) ) ;
m_properties - > setSubsampling ( oldSl - > m_properties - > getSubsampling ( ) ) ;
}
//-----------------------------------------------------------------------------
TPalette * TXshSimpleLevel : : getPalette ( ) const
{
return m_palette ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : setPalette ( TPalette * palette )
{
if ( m_palette ! = palette ) {
if ( m_palette )
m_palette - > release ( ) ;
m_palette = palette ;
if ( m_palette ) {
m_palette - > addRef ( ) ;
if ( ! ( getType ( ) & FULLCOLOR_TYPE ) )
m_palette - > setPaletteName ( getName ( ) ) ;
}
}
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : getFids ( std : : vector < TFrameId > & fids ) const
{
fids . assign ( m_frames . begin ( ) , m_frames . end ( ) ) ;
}
//-----------------------------------------------------------------------------
std : : vector < TFrameId > TXshSimpleLevel : : getFids ( ) const
{
return std : : vector < TFrameId > ( m_frames . begin ( ) , m_frames . end ( ) ) ;
}
//-----------------------------------------------------------------------------
bool TXshSimpleLevel : : isFid ( const TFrameId & fid ) const
{
return m_frames . count ( fid ) ;
}
//-----------------------------------------------------------------------------
const TFrameId & TXshSimpleLevel : : getFrameId ( int index ) const
{
return * ( m_frames . begin ( ) + = index ) ;
}
//-----------------------------------------------------------------------------
TFrameId TXshSimpleLevel : : getFirstFid ( ) const
{
return ! isEmpty ( ) ? * m_frames . begin ( ) : TFrameId ( TFrameId : : NO_FRAME ) ;
}
//-----------------------------------------------------------------------------
TFrameId TXshSimpleLevel : : getLastFid ( ) const
{
return ! isEmpty ( ) ? * m_frames . rbegin ( ) : TFrameId ( TFrameId : : NO_FRAME ) ;
}
//-----------------------------------------------------------------------------
int TXshSimpleLevel : : guessStep ( ) const
{
int frameCount = m_frames . size ( ) ;
if ( frameCount < 2 )
return 1 ; // un livello con zero o un frame ha per def. step=1
FramesSet : : const_iterator ft = m_frames . begin ( ) ;
TFrameId firstFid = * ft + + ,
secondFid = * ft + + ;
if ( firstFid . getLetter ( ) ! = 0 | | secondFid . getLetter ( ) ! = 0 )
return 1 ;
int step = secondFid . getNumber ( ) - firstFid . getNumber ( ) ;
if ( step = = 1 )
return 1 ;
// controllo subito se lo step vale per l'ultimo frame
// (cerco di limitare il numero di volte in cui devo controllare tutta la lista)
TFrameId lastFid = * m_frames . rbegin ( ) ;
if ( lastFid . getLetter ( ) ! = 0 )
return 1 ;
if ( lastFid . getNumber ( ) ! = firstFid . getNumber ( ) + step * ( frameCount - 1 ) )
return 1 ;
for ( int i = 2 ; ft ! = m_frames . end ( ) ; + + ft , + + i ) {
const TFrameId & fid = * ft ;
if ( fid . getLetter ( ) ! = 0 )
return 1 ;
if ( fid . getNumber ( ) ! = firstFid . getNumber ( ) + step * i )
return 1 ;
}
return step ;
}
//-----------------------------------------------------------------------------
int TXshSimpleLevel : : fid2index ( const TFrameId & fid ) const
{
FramesSet : : const_iterator ft = m_frames . find ( fid ) ;
return ( ft ! = m_frames . end ( ) ) ? std : : distance ( m_frames . begin ( ) , ft ) : // Note: flat_set has random access
- 1 ; // iterators, so this is FAST
}
//-----------------------------------------------------------------------------
int TXshSimpleLevel : : guessIndex ( const TFrameId & fid ) const
{
if ( m_frames . empty ( ) )
return 0 ; // no frames, return 0 (by definition)
FramesSet : : const_iterator ft = m_frames . lower_bound ( fid ) ;
if ( ft = = m_frames . end ( ) ) {
const TFrameId & maxFid = * m_frames . rbegin ( ) ;
assert ( fid > maxFid ) ;
// fid not in the table, but greater than the last one.
// return a suitable index. (e.g. frames are 1,3,5,7; fid2index(11) should return index=5)
int step = guessStep ( ) ;
int i = ( fid . getNumber ( ) - maxFid . getNumber ( ) ) / step ;
return m_frames . size ( ) - 1 + i ;
} else
return std : : distance ( m_frames . begin ( ) , ft ) ;
}
//-----------------------------------------------------------------------------
TFrameId TXshSimpleLevel : : index2fid ( int index ) const
{
if ( index < 0 )
return TFrameId ( - 2 ) ;
int frameCount = m_frames . size ( ) ;
if ( frameCount = = 0 )
return TFrameId ( 1 ) ; // o_o?
if ( index < frameCount ) {
FramesSet : : const_iterator ft = m_frames . begin ( ) ;
std : : advance ( ft , index ) ;
return * ft ;
} else {
int step = guessStep ( ) ;
TFrameId maxFid = * m_frames . rbegin ( ) ;
int d = step * ( index - frameCount + 1 ) ;
return TFrameId ( maxFid . getNumber ( ) + d ) ;
}
}
//-----------------------------------------------------------------------------
TImageP TXshSimpleLevel : : getFrame ( const TFrameId & fid , UCHAR imFlags , int subsampling ) const
{
assert ( m_type ! = UNKNOWN_XSHLEVEL ) ;
// If the required frame is not in range, quit
if ( m_frames . count ( fid ) = = 0 )
return TImageP ( ) ;
2016-04-19 19:32:17 +12:00
const std : : string & imgId = getImageId ( fid ) ;
2016-03-19 06:57:51 +13:00
ImageLoader : : BuildExtData extData ( this , fid , subsampling ) ;
TImageP img = ImageManager : : instance ( ) - > getImage (
imgId , imFlags , & extData ) ;
if ( imFlags & ImageManager : : toBeModified ) {
// The image will be modified. Perform any related invalidation.
texture_utils : : invalidateTexture ( this , fid ) ; // We must rebuild associated textures
}
return img ;
}
//-----------------------------------------------------------------------------
TImageInfo * TXshSimpleLevel : : getFrameInfo ( const TFrameId & fid , bool toBeModified )
{
assert ( m_type ! = UNKNOWN_XSHLEVEL ) ;
// If the required frame is not in range, quit
if ( m_frames . count ( fid ) = = 0 )
return 0 ;
2016-04-19 19:32:17 +12:00
const std : : string & imgId = getImageId ( fid ) ;
2016-03-19 06:57:51 +13:00
TImageInfo * info = ImageManager : : instance ( ) - > getInfo (
imgId , toBeModified ? ImageManager : : toBeModified : ImageManager : : none , 0 ) ;
return info ;
}
//-----------------------------------------------------------------------------
TImageP TXshSimpleLevel : : getFrameIcon ( const TFrameId & fid ) const
{
assert ( m_type ! = UNKNOWN_XSHLEVEL ) ;
if ( m_frames . count ( fid ) = = 0 )
return TImageP ( ) ;
// NOTE: Icons caching is DISABLED at this stage. It is now responsibility of
// ToonzQt's IconGenerator class.
ImageLoader : : BuildExtData extData ( this , fid ) ;
extData . m_subs = 1 , extData . m_icon = true ;
const std : : string & imgId = getImageId ( fid ) ;
TImageP img = ImageManager : : instance ( ) - > getImage ( imgId , ImageManager : : dontPutInCache , & extData ) ;
TToonzImageP timg = ( TToonzImageP ) img ;
if ( timg & & m_palette )
timg - > setPalette ( m_palette ) ;
return img ;
}
//-----------------------------------------------------------------------------
// load icon (and image) data of all frames into cache
void TXshSimpleLevel : : loadAllIconsAndPutInCache ( bool cacheImagesAsWell )
{
if ( m_type ! = TZP_XSHLEVEL )
return ;
std : : vector < TFrameId > fids ;
getFids ( fids ) ;
std : : vector < std : : string > iconIds ;
for ( int i = 0 ; i < ( int ) fids . size ( ) ; i + + ) {
iconIds . push_back ( getIconId ( fids [ i ] ) ) ;
}
ImageManager : : instance ( ) - > loadAllTlvIconsAndPutInCache ( this , fids , iconIds , cacheImagesAsWell ) ;
}
//-----------------------------------------------------------------------------
TRasterImageP TXshSimpleLevel : : getFrameToCleanup ( const TFrameId & fid ) const
{
assert ( m_type ! = UNKNOWN_XSHLEVEL ) ;
FramesSet : : const_iterator ft = m_frames . find ( fid ) ;
if ( ft = = m_frames . end ( ) )
return TImageP ( ) ;
bool flag = ( m_scannedPath ! = TFilePath ( ) ) ;
2016-04-19 19:32:17 +12:00
std : : string imageId = getImageId ( fid , flag ? Scanned : 0 ) ;
2016-03-19 06:57:51 +13:00
ImageLoader : : BuildExtData extData ( this , fid , 1 ) ;
TRasterImageP img = ImageManager : : instance ( ) - > getImage ( imageId , ImageManager : : dontPutInCache , & extData ) ;
if ( ! img )
return img ;
double x_dpi , y_dpi ;
img - > getDpi ( x_dpi , y_dpi ) ;
if ( ! x_dpi & & ! y_dpi ) {
TPointD dpi = m_properties - > getDpi ( ) ;
img - > setDpi ( dpi . x , dpi . y ) ;
}
return img ;
}
//-----------------------------------------------------------------------------
TImageP TXshSimpleLevel : : getFullsampledFrame ( const TFrameId & fid , UCHAR imFlags ) const
{
assert ( m_type ! = UNKNOWN_XSHLEVEL ) ;
FramesSet : : const_iterator it = m_frames . find ( fid ) ;
if ( it = = m_frames . end ( ) )
return TRasterImageP ( ) ;
2016-04-19 19:32:17 +12:00
std : : string imageId = getImageId ( fid ) ;
2016-03-19 06:57:51 +13:00
ImageLoader : : BuildExtData extData ( this , fid , 1 ) ;
TImageP img = ImageManager : : instance ( ) - > getImage ( imageId , imFlags , & extData ) ;
if ( imFlags & ImageManager : : toBeModified ) {
// The image will be modified. Perform any related invalidation.
texture_utils : : invalidateTexture ( this , fid ) ; // We must rebuild associated textures
}
return img ;
}
//-----------------------------------------------------------------------------
2016-04-19 19:32:17 +12:00
std : : string TXshSimpleLevel : : getIconId ( const TFrameId & fid , int frameStatus ) const
2016-03-19 06:57:51 +13:00
{
return " icon: " + getImageId ( fid , frameStatus ) ;
}
//-----------------------------------------------------------------------------
2016-04-19 19:32:17 +12:00
std : : string TXshSimpleLevel : : getIconId ( const TFrameId & fid , const TDimension & size ) const
2016-03-19 06:57:51 +13:00
{
return getImageId ( fid ) + " : " + toString ( size . lx ) + " x " + toString ( size . ly ) ;
}
//-----------------------------------------------------------------------------
namespace
{
TAffine getAffine ( const TDimension & srcSize , const TDimension & dstSize )
{
double scx = 1 * dstSize . lx / ( double ) srcSize . lx ;
double scy = 1 * dstSize . ly / ( double ) srcSize . ly ;
double sc = tmin ( scx , scy ) ;
double dx = ( dstSize . lx - srcSize . lx * sc ) * 0.5 ;
double dy = ( dstSize . ly - srcSize . ly * sc ) * 0.5 ;
return TScale ( sc ) * TTranslation ( 0.5 * TPointD ( srcSize . lx , srcSize . ly ) + TPointD ( dx , dy ) ) ;
}
//-----------------------------------------------------------------------------
/*!Costruisce l'icona di dimesione \b size dell'immagine \b img.*/
TImageP buildIcon ( const TImageP & img , const TDimension & size )
{
TRaster32P raster ( size ) ;
if ( TVectorImageP vi = img ) {
TOfflineGL * glContext = new TOfflineGL ( size ) ;
TDimension cameraSize ( 768 , 576 ) ;
TPalette * vPalette = img - > getPalette ( ) ;
assert ( vPalette ) ;
const TVectorRenderData rd (
getAffine ( cameraSize , size ) ,
TRect ( ) ,
vPalette ,
0 , false ) ;
glContext - > clear ( TPixel32 : : White ) ;
glContext - > draw ( vi , rd ) ;
raster - > copy ( glContext - > getRaster ( ) ) ;
delete glContext ;
} else if ( TToonzImageP ti = img ) {
raster - > fill ( TPixel32 ( 255 , 255 , 255 , 255 ) ) ;
TRasterCM32P rasCM32 = ti - > getRaster ( ) ;
TRect bbox ;
bbox = ti - > getSavebox ( ) ;
if ( ! bbox . isEmpty ( ) ) {
rasCM32 = rasCM32 - > extractT ( bbox ) ;
double sx = raster - > getLx ( ) / ( double ) rasCM32 - > getLx ( ) ;
double sy = raster - > getLy ( ) / ( double ) rasCM32 - > getLy ( ) ;
double sc = tmin ( sx , sy ) ;
TAffine aff = TScale ( sc ) . place (
rasCM32 - > getCenterD ( ) ,
raster - > getCenterD ( ) ) ;
TRop : : resample (
raster ,
rasCM32 ,
ti - > getPalette ( ) ,
aff ) ;
raster - > lock ( ) ;
for ( int y = 0 ; y < raster - > getLy ( ) ; y + + ) {
TPixel32 * pix = raster - > pixels ( y ) ;
TPixel32 * endPix = pix + raster - > getLx ( ) ;
while ( pix < endPix ) {
* pix = overPix ( TPixel32 : : White , * pix ) ;
pix + + ;
}
}
raster - > unlock ( ) ;
}
} else {
TRasterImageP ri = img ;
if ( ri ) {
ri - > makeIcon ( raster ) ;
TRop : : addBackground ( raster , TPixel32 : : White ) ;
} else
raster - > fill ( TPixel32 ( 127 , 50 , 20 ) ) ;
}
return TRasterImageP ( raster ) ;
}
} // anonymous namespace
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : setFrame ( const TFrameId & fid , const TImageP & img )
{
assert ( m_type ! = UNKNOWN_XSHLEVEL ) ;
if ( img )
img - > setPalette ( getPalette ( ) ) ;
m_frames . insert ( fid ) ;
TFilePath path = m_path ;
int frameStatus = getFrameStatus ( fid ) ;
static const int SCANNED_OR_CLEANUPPED = ( Scanned | Cleanupped ) ;
if ( ( frameStatus & SCANNED_OR_CLEANUPPED ) = = Scanned )
path = m_scannedPath ;
// Deal with the ImageManger: ensure the identifiers are bound, and the
// associated image is either modified to img or (if !img) invalidated.
2016-04-19 19:32:17 +12:00
const std : : string & imageId = getImageId ( fid ) ;
2016-03-19 06:57:51 +13:00
if ( ! ImageManager : : instance ( ) - > isBound ( imageId ) ) {
const TFilePath & decodedPath = getScene ( ) - > decodeFilePath ( path ) ;
ImageManager : : instance ( ) - > bind ( imageId , new ImageLoader ( decodedPath , fid ) ) ;
}
ImageManager : : instance ( ) - > setImage ( imageId , img ) ; // Invalidates if !img
if ( frameStatus = = Normal ) {
// Only a normal frame can have these. Justified since:
// a) PLIs have nothing to share with cleanup stuff
// b) The latter is used only in LineTest - which does not have Cleanup
if ( m_type = = PLI_XSHLEVEL ) {
2016-04-19 19:32:17 +12:00
const std : : string & imageId2 = rasterized ( imageId ) ;
2016-03-19 06:57:51 +13:00
if ( ! ImageManager : : instance ( ) - > isBound ( imageId2 ) )
ImageManager : : instance ( ) - > bind ( imageId2 , new ImageRasterizer ) ;
else
ImageManager : : instance ( ) - > invalidate ( imageId2 ) ;
}
if ( m_type = = OVL_XSHLEVEL | | m_type = = TZI_XSHLEVEL ) {
2016-04-19 19:32:17 +12:00
const std : : string & imageId2 = filled ( imageId ) ;
2016-03-19 06:57:51 +13:00
if ( ! ImageManager : : instance ( ) - > isBound ( imageId2 ) )
ImageManager : : instance ( ) - > bind ( imageId2 , new ImageFiller ) ;
else
ImageManager : : instance ( ) - > invalidate ( imageId2 ) ;
}
}
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : eraseFrame ( const TFrameId & fid )
{
FramesSet : : iterator ft = m_frames . find ( fid ) ;
if ( ft = = m_frames . end ( ) )
return ;
// Erase the corresponding entry in the renumber table
std : : map < TFrameId , TFrameId > : : iterator rt , rEnd ( m_renumberTable . end ( ) ) ;
for ( rt = m_renumberTable . begin ( ) ; rt ! = rEnd ; + + rt ) {
if ( rt - > second = = fid ) {
m_renumberTable . erase ( rt - > first ) ;
break ;
}
}
m_frames . erase ( ft ) ;
getHookSet ( ) - > eraseFrame ( fid ) ;
ImageManager * im = ImageManager : : instance ( ) ;
{
im - > unbind ( getImageId ( fid , Normal ) ) ;
im - > unbind ( getImageId ( fid , Scanned ) ) ;
im - > unbind ( getImageId ( fid , CleanupPreview ) ) ;
if ( m_type = = PLI_XSHLEVEL )
im - > unbind ( rasterized ( getImageId ( fid ) ) ) ;
if ( m_type = = OVL_XSHLEVEL | | m_type = = TZI_XSHLEVEL )
im - > unbind ( filled ( getImageId ( fid ) ) ) ;
texture_utils : : invalidateTexture ( this , fid ) ;
}
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : clearFrames ( )
{
ImageManager * im = ImageManager : : instance ( ) ;
// Unbind frames
FramesSet : : iterator ft , fEnd = m_frames . end ( ) ;
for ( ft = m_frames . begin ( ) ; ft ! = fEnd ; + + ft ) {
im - > unbind ( getImageId ( * ft , Scanned ) ) ;
im - > unbind ( getImageId ( * ft , Cleanupped ) ) ;
im - > unbind ( getImageId ( * ft , CleanupPreview ) ) ;
if ( m_type = = PLI_XSHLEVEL )
im - > unbind ( rasterized ( getImageId ( * ft ) ) ) ;
if ( m_type = = OVL_XSHLEVEL | | m_type = = TZI_XSHLEVEL )
im - > unbind ( filled ( getImageId ( * ft ) ) ) ;
texture_utils : : invalidateTexture ( this , * ft ) ;
}
// Clear level
m_frames . clear ( ) ;
m_editableRange . clear ( ) ;
m_editableRangeUserInfo . clear ( ) ;
m_renumberTable . clear ( ) ;
m_framesStatus . clear ( ) ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : loadData ( TIStream & is )
{
2016-04-19 19:32:17 +12:00
std : : string tagName ;
2016-03-19 06:57:51 +13:00
bool flag = false ;
int type = UNKNOWN_XSHLEVEL ;
for ( ; ; ) {
if ( is . matchTag ( tagName ) ) {
if ( tagName = = " path " ) {
is > > m_path ;
is . matchEndTag ( ) ;
} else if ( tagName = = " scannedPath " ) {
is > > m_scannedPath ;
is . matchEndTag ( ) ;
} else if ( tagName = = " info " ) {
2016-04-19 19:32:17 +12:00
std : : string v ;
2016-03-19 06:57:51 +13:00
double xdpi = 0 , ydpi = 0 ;
int subsampling = 1 ;
int doPremultiply = 0 ;
int whiteTransp = 0 ;
int antialiasSoftness = 0 ;
LevelProperties : : DpiPolicy dpiPolicy = LevelProperties : : DP_ImageDpi ;
if ( is . getTagParam ( " dpix " , v ) )
xdpi = toDouble ( v ) ;
if ( is . getTagParam ( " dpiy " , v ) )
ydpi = toDouble ( v ) ;
if ( xdpi ! = 0 & & ydpi ! = 0 )
dpiPolicy = LevelProperties : : DP_CustomDpi ;
2016-04-19 19:32:17 +12:00
std : : string dpiType = is . getTagAttribute ( " dpiType " ) ;
2016-03-19 06:57:51 +13:00
if ( dpiType = = " image " )
dpiPolicy = LevelProperties : : DP_ImageDpi ;
if ( is . getTagParam ( " type " , v ) & & v = = " s " )
type = TZI_XSHLEVEL ;
if ( is . getTagParam ( " subsampling " , v ) )
subsampling = toInt ( v ) ;
if ( is . getTagParam ( " premultiply " , v ) )
doPremultiply = toInt ( v ) ;
if ( is . getTagParam ( " antialias " , v ) )
antialiasSoftness = toInt ( v ) ;
if ( is . getTagParam ( " whiteTransp " , v ) )
whiteTransp = toInt ( v ) ;
m_properties - > setDpiPolicy ( dpiPolicy ) ;
m_properties - > setDpi ( TPointD ( xdpi , ydpi ) ) ;
m_properties - > setSubsampling ( subsampling ) ;
m_properties - > setDoPremultiply ( doPremultiply ) ;
m_properties - > setDoAntialias ( antialiasSoftness ) ;
m_properties - > setWhiteTransp ( whiteTransp ) ;
} else
throw TException ( " unexpected tag " + tagName ) ;
} else {
if ( flag )
break ; // ci puo' essere un solo nome
flag = true ;
2016-04-19 19:32:17 +12:00
std : : wstring token ;
2016-03-19 06:57:51 +13:00
is > > token ;
if ( token = = L " __empty " ) {
// empty = true;
is > > token ;
}
if ( token = = L " _raster " ) // obsoleto (Tab2.2)
{
double xdpi = 1 , ydpi = 1 ;
is > > xdpi > > ydpi > > m_name ;
setName ( m_name ) ;
type = OVL_XSHLEVEL ;
m_properties - > setDpi ( TPointD ( xdpi , ydpi ) ) ;
setType ( type ) ;
setPath ( TFilePath ( " +drawings/ " ) + ( getName ( ) + L " . " + toWideString ( " bmp " ) ) , true ) ;
} else if ( token = = L " __raster " ) // obsoleto (Tab2.2)
{
double xdpi = 1 , ydpi = 1 ;
2016-04-19 19:32:17 +12:00
std : : string extension ;
2016-03-19 06:57:51 +13:00
is > > xdpi > > ydpi > > m_name > > extension ;
setName ( m_name ) ;
type = OVL_XSHLEVEL ;
m_properties - > setDpi ( TPointD ( xdpi , ydpi ) ) ;
setType ( type ) ;
setPath ( TFilePath ( " +drawings/ " ) + ( getName ( ) + L " . " + toWideString ( extension ) ) , true ) ;
} else {
m_name = token ;
setName ( m_name ) ;
}
}
}
if ( type = = UNKNOWN_XSHLEVEL ) {
2016-04-19 19:32:17 +12:00
std : : string ext = m_path . getType ( ) ;
2016-03-19 06:57:51 +13:00
if ( ext = = " pli " | | ext = = " svg " )
type = PLI_XSHLEVEL ;
else if ( ext = = " tlv " | | ext = = " tzu " | | ext = = " tzp " | | ext = = " tzl " )
type = TZP_XSHLEVEL ;
else if ( ext = = " tzi " )
type = TZI_XSHLEVEL ;
else if ( ext = = " mesh " )
type = MESH_XSHLEVEL ;
else
type = OVL_XSHLEVEL ;
}
setType ( type ) ;
}
//-----------------------------------------------------------------------------
namespace
{
class LoadingLevelRange
{
public :
TFrameId m_fromFid , m_toFid ;
LoadingLevelRange ( ) : m_fromFid ( 1 ) , m_toFid ( 0 ) { }
bool match ( const TFrameId & fid ) const
{
/*-- ↓SubSequent範囲内にある条件 ↓全部ロードする場合 --*/
return m_fromFid < = fid & & fid < = m_toFid | | m_fromFid > m_toFid ;
}
bool isEnabled ( ) const
{
return m_fromFid < = m_toFid ;
}
void reset ( )
{
m_fromFid = TFrameId ( 1 ) ;
m_toFid = TFrameId ( 0 ) ;
}
} loadingLevelRange ;
//-----------------------------------------------------------------------------
} // namespace
//-----------------------------------------------------------------------------
void setLoadingLevelRange ( const TFrameId & fromFid , const TFrameId & toFid )
{
loadingLevelRange . m_fromFid = fromFid ;
loadingLevelRange . m_toFid = toFid ;
}
void getLoadingLevelRange ( TFrameId & fromFid , TFrameId & toFid )
{
fromFid = loadingLevelRange . m_fromFid ;
toFid = loadingLevelRange . m_toFid ;
}
TFilePath getLevelPathAndSetNameWithPsdLevelName ( TXshSimpleLevel * xshLevel )
{
TFilePath retfp = xshLevel - > getPath ( ) ;
QString name = QString : : fromStdWString ( retfp . getWideName ( ) ) ;
QStringList list = name . split ( " # " ) ;
if ( list . size ( ) > = 2 & & list . at ( 1 ) ! = " frames " ) {
bool hasLayerId ;
int layid = list . at ( 1 ) . toInt ( & hasLayerId ) ;
if ( hasLayerId ) {
// An explicit photoshop layer id must be converted to the associated level name
TPSDParser psdparser ( xshLevel - > getScene ( ) - > decodeFilePath ( retfp ) ) ;
std : : string levelName = psdparser . getLevelNameWithCounter ( layid ) ; // o_o what about UNICODE names??
list [ 1 ] = QString : : fromStdString ( levelName ) ;
std : : wstring wLevelName = list . join ( " # " ) . toStdWString ( ) ;
retfp = retfp . withName ( wLevelName ) ;
TLevelSet * levelSet = xshLevel - > getScene ( ) - > getLevelSet ( ) ;
if ( levelSet & & levelSet - > hasLevel ( wLevelName ) ) // levelSet should be asserted instead
levelSet - > renameLevel ( xshLevel , wLevelName ) ;
xshLevel - > setName ( wLevelName ) ;
}
}
return retfp ;
}
//-----------------------------------------------------------------------------
// Nota: load() NON fa clearFrames(). si limita ad aggiungere le informazioni
// relative ai frames su disco
void TXshSimpleLevel : : load ( )
{
getProperties ( ) - > setCreator ( " " ) ;
QString creator ;
assert ( getScene ( ) ) ;
if ( ! getScene ( ) )
return ;
2016-04-20 20:30:15 +12:00
2016-03-19 06:57:51 +13:00
m_isSubsequence = loadingLevelRange . isEnabled ( ) ;
TFilePath checkpath = getScene ( ) - > decodeFilePath ( m_path ) ;
2016-04-19 19:32:17 +12:00
std : : string type = checkpath . getType ( ) ;
2016-03-19 06:57:51 +13:00
if ( m_scannedPath ! = TFilePath ( ) ) {
getProperties ( ) - > setDirtyFlag ( false ) ; // Level is now supposedly loaded from disk
static const int ScannedCleanuppedMask = Scanned | Cleanupped ;
TFilePath path = getScene ( ) - > decodeFilePath ( m_scannedPath ) ;
if ( TSystem : : doesExistFileOrLevel ( path ) ) {
TLevelReaderP lr ( path ) ;
assert ( lr ) ;
TLevelP level = lr - > loadInfo ( ) ;
if ( ! checkCreatorString ( creator = lr - > getCreator ( ) ) )
getProperties ( ) - > setIsForbidden ( true ) ;
else
for ( TLevel : : Iterator it = level - > begin ( ) ; it ! = level - > end ( ) ; it + + ) {
TFrameId fid = it - > first ;
if ( ! loadingLevelRange . match ( fid ) )
continue ;
setFrameStatus ( fid , ( getFrameStatus ( fid ) & ~ ScannedCleanuppedMask ) | Scanned ) ;
setFrame ( fid , TImageP ( ) ) ;
}
}
path = getScene ( ) - > decodeFilePath ( m_path ) ;
if ( TSystem : : doesExistFileOrLevel ( path ) ) {
TLevelReaderP lr ( path ) ;
assert ( lr ) ;
TLevelP level = lr - > loadInfo ( ) ;
if ( getType ( ) & FULLCOLOR_TYPE )
setPalette ( FullColorPalette : : instance ( ) - > getPalette ( getScene ( ) ) ) ;
else
setPalette ( level - > getPalette ( ) ) ;
if ( ! checkCreatorString ( creator = lr - > getCreator ( ) ) )
getProperties ( ) - > setIsForbidden ( true ) ;
else
for ( TLevel : : Iterator it = level - > begin ( ) ; it ! = level - > end ( ) ; it + + ) {
TFrameId fid = it - > first ;
if ( ! loadingLevelRange . match ( fid ) )
continue ;
setFrameStatus ( fid , getFrameStatus ( fid ) | Cleanupped ) ;
setFrame ( fid , TImageP ( ) ) ;
}
setContentHistory ( lr - > getContentHistory ( ) ? lr - > getContentHistory ( ) - > clone ( ) : 0 ) ;
}
} else {
// Not a scan + cleanup level
if ( m_path . getType ( ) = = " psd " & & this - > getScene ( ) - > getVersionNumber ( ) . first < 71 )
m_path = getLevelPathAndSetNameWithPsdLevelName ( this ) ;
TFilePath path = getScene ( ) - > decodeFilePath ( m_path ) ;
getProperties ( ) - > setDirtyFlag ( false ) ; // Level is now supposedly loaded from disk
TLevelReaderP lr ( path ) ; // May throw
assert ( lr ) ;
TLevelP level = lr - > loadInfo ( ) ;
if ( level - > getFrameCount ( ) > 0 ) {
const TImageInfo * info = lr - > getImageInfo ( level - > begin ( ) - > first ) ;
if ( info & & info - > m_samplePerPixel > = 5 ) {
QString msg = QString ( " Failed to open %1. \n Samples per pixel is more than 4. It may containt more than one alpha channel. " ) . arg ( QString : : fromStdWString ( m_path . getWideString ( ) ) ) ;
QMessageBox : : warning ( 0 , " Image format not supported " , msg ) ;
return ;
}
if ( info )
set16BitChannelLevel ( info - > m_bitsPerSample = = 16 ) ;
}
if ( ( getType ( ) & FULLCOLOR_TYPE ) & & ! is16BitChannelLevel ( ) )
setPalette ( FullColorPalette : : instance ( ) - > getPalette ( getScene ( ) ) ) ;
else
setPalette ( level - > getPalette ( ) ) ;
if ( ! checkCreatorString ( creator = lr - > getCreator ( ) ) )
getProperties ( ) - > setIsForbidden ( true ) ;
else
for ( TLevel : : Iterator it = level - > begin ( ) ; it ! = level - > end ( ) ; it + + ) {
m_renumberTable [ it - > first ] = it - > first ; //Voglio che la tabella contenga anche i frame che non vengono caricati
if ( ! loadingLevelRange . match ( it - > first ) )
continue ;
setFrame ( it - > first , TImageP ( ) ) ;
}
setContentHistory ( lr - > getContentHistory ( ) ? lr - > getContentHistory ( ) - > clone ( ) : 0 ) ;
}
getProperties ( ) - > setCreator ( creator . toStdString ( ) ) ;
loadingLevelRange . reset ( ) ;
if ( getType ( ) ! = PLI_XSHLEVEL ) {
if ( m_properties - > getImageDpi ( ) = = TPointD ( ) & & ! m_frames . empty ( ) ) {
TDimension imageRes ( 0 , 0 ) ;
TPointD imageDpi ;
const TFrameId & firstFid = getFirstFid ( ) ;
2016-04-19 19:32:17 +12:00
std : : string imageId = getImageId ( firstFid ) ;
2016-03-19 06:57:51 +13:00
const TImageInfo * imageInfo = ImageManager : : instance ( ) - > getInfo ( imageId , ImageManager : : none , 0 ) ;
if ( imageInfo ) {
imageRes . lx = imageInfo - > m_lx ;
imageRes . ly = imageInfo - > m_ly ;
imageDpi . x = imageInfo - > m_dpix ;
imageDpi . y = imageInfo - > m_dpiy ;
m_properties - > setImageDpi ( imageDpi ) ;
m_properties - > setImageRes ( imageRes ) ;
m_properties - > setBpp ( imageInfo - > m_bitsPerSample * imageInfo - > m_samplePerPixel ) ;
}
}
setRenumberTable ( ) ;
}
if ( getPalette ( ) & & StudioPalette : : isEnabled ( ) )
StudioPalette : : instance ( ) - > updateLinkedColors ( getPalette ( ) ) ;
TFilePath refImgName ;
if ( m_palette ) {
refImgName = m_palette - > getRefImgPath ( ) ;
TFilePath refImgPath = refImgName ;
if ( refImgName ! = TFilePath ( ) & &
TFileStatus ( refImgPath ) . doesExist ( ) ) {
TLevelReaderP lr ( refImgPath ) ;
if ( lr ) {
TLevelP level = lr - > loadInfo ( ) ;
if ( level - > getFrameCount ( ) > 0 ) {
TImageP img = lr - > getFrameReader ( level - > begin ( ) - > first ) - > load ( ) ;
if ( img & & getPalette ( ) ) {
img - > setPalette ( 0 ) ;
getPalette ( ) - > setRefImg ( img ) ;
std : : vector < TFrameId > fids ;
for ( TLevel : : Iterator it = level - > begin ( ) ; it ! = level - > end ( ) ; + + it )
fids . push_back ( it - > first ) ;
getPalette ( ) - > setRefLevelFids ( fids ) ;
}
}
}
}
}
// Load hooks
HookSet * hookSet = getHookSet ( ) ;
hookSet - > clearHooks ( ) ;
const TFilePath & hookFile = TXshSimpleLevel : : getExistingHookFile (
getScene ( ) - > decodeFilePath ( m_path ) ) ;
if ( ! hookFile . isEmpty ( ) ) {
TIStream is ( hookFile ) ;
2016-04-19 19:32:17 +12:00
std : : string tagName ;
2016-03-19 06:57:51 +13:00
try {
if ( is . matchTag ( tagName ) & & tagName = = " hooks " )
hookSet - > loadData ( is ) ;
} catch ( . . . ) {
}
}
updateReadOnly ( ) ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : load ( const std : : vector < TFrameId > & fIds )
{
getProperties ( ) - > setCreator ( " " ) ;
QString creator ;
assert ( getScene ( ) ) ;
getProperties ( ) - > setDirtyFlag ( false ) ;
m_isSubsequence = loadingLevelRange . isEnabled ( ) ;
// non e' un livello scan+cleanup
TFilePath path = getScene ( ) - > decodeFilePath ( m_path ) ;
TLevelReaderP lr ( path ) ;
assert ( lr ) ;
if ( ! checkCreatorString ( creator = lr - > getCreator ( ) ) )
getProperties ( ) - > setIsForbidden ( true ) ;
else {
if ( fIds . size ( ) ! = 0 ) {
for ( int i = 0 ; i < ( int ) fIds . size ( ) ; i + + ) {
m_renumberTable [ fIds [ i ] ] = fIds [ i ] ;
if ( ! loadingLevelRange . match ( fIds [ i ] ) )
continue ;
setFrame ( fIds [ i ] , TImageP ( ) ) ;
}
} else {
TLevelP level = lr - > loadInfo ( ) ;
for ( TLevel : : Iterator it = level - > begin ( ) ; it ! = level - > end ( ) ; it + + ) {
m_renumberTable [ it - > first ] = it - > first ;
if ( ! loadingLevelRange . match ( it - > first ) )
continue ;
setFrame ( it - > first , TImageP ( ) ) ;
}
}
}
setContentHistory ( lr - > getContentHistory ( ) ? lr - > getContentHistory ( ) - > clone ( ) : 0 ) ;
getProperties ( ) - > setCreator ( creator . toStdString ( ) ) ;
loadingLevelRange . reset ( ) ;
if ( getType ( ) ! = PLI_XSHLEVEL ) {
if ( m_properties - > getImageDpi ( ) = = TPointD ( ) & & ! m_frames . empty ( ) ) {
TDimension imageRes ( 0 , 0 ) ;
TPointD imageDpi ;
2016-04-19 19:32:17 +12:00
std : : string imageId = getImageId ( getFirstFid ( ) ) ;
2016-03-19 06:57:51 +13:00
const TImageInfo * imageInfo = ImageManager : : instance ( ) - > getInfo ( imageId , ImageManager : : none , 0 ) ;
if ( imageInfo ) {
imageRes . lx = imageInfo - > m_lx ;
imageRes . ly = imageInfo - > m_ly ;
imageDpi . x = imageInfo - > m_dpix ;
imageDpi . y = imageInfo - > m_dpiy ;
m_properties - > setImageDpi ( imageDpi ) ;
m_properties - > setImageRes ( imageRes ) ;
}
}
setRenumberTable ( ) ;
}
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : updateReadOnly ( )
{
TFilePath path = getScene ( ) - > decodeFilePath ( m_path ) ;
m_isReadOnly = isAreadOnlyLevel ( path ) ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : saveData ( TOStream & os )
{
os < < m_name ;
2016-04-19 19:32:17 +12:00
std : : map < std : : string , std : : string > attr ;
2016-03-19 06:57:51 +13:00
if ( getProperties ( ) - > getDpiPolicy ( ) = = LevelProperties : : DP_CustomDpi ) {
TPointD dpi = getProperties ( ) - > getDpi ( ) ;
if ( dpi . x ! = 0 & & dpi . y ! = 0 ) {
attr [ " dpix " ] = toString ( dpi . x ) ;
attr [ " dpiy " ] = toString ( dpi . y ) ;
}
} else {
attr [ " dpiType " ] = " image " ;
}
if ( getProperties ( ) - > getSubsampling ( ) ! = 1 ) {
attr [ " subsampling " ] = toString ( getProperties ( ) - > getSubsampling ( ) ) ;
}
if ( getProperties ( ) - > antialiasSoftness ( ) > 0 ) {
attr [ " antialias " ] = toString ( getProperties ( ) - > antialiasSoftness ( ) ) ;
}
if ( getProperties ( ) - > doPremultiply ( ) ) {
attr [ " premultiply " ] = toString ( getProperties ( ) - > doPremultiply ( ) ) ;
} else if ( getProperties ( ) - > whiteTransp ( ) ) {
attr [ " whiteTransp " ] = toString ( getProperties ( ) - > whiteTransp ( ) ) ;
}
if ( m_type = = TZI_XSHLEVEL )
attr [ " type " ] = " s " ;
os . openCloseChild ( " info " , attr ) ;
os . child ( " path " ) < < m_path ; // fp;
if ( m_scannedPath ! = TFilePath ( ) )
os . child ( " scannedPath " ) < < m_scannedPath ; // fp;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : save ( )
{
assert ( getScene ( ) ) ;
TFilePath path = getScene ( ) - > decodeFilePath ( m_path ) ;
TSystem : : outputDebug ( " save() : " + toString ( m_path ) + " = " + toString ( path ) + " \n " ) ;
if ( getProperties ( ) - > getDirtyFlag ( ) = = false & &
getPalette ( ) - > getDirtyFlag ( ) = = false & &
TSystem : : doesExistFileOrLevel ( path ) )
return ;
if ( ! TFileStatus ( path . getParentDir ( ) ) . doesExist ( ) ) {
try {
TSystem : : mkDir ( path . getParentDir ( ) ) ;
} catch ( . . . ) {
}
}
save ( path ) ;
}
//-----------------------------------------------------------------------------
void saveBackup ( TFilePath path )
{
try {
TFilePath backup = path . withName ( path . getName ( ) + " _backup " ) ;
if ( TSystem : : doesExistFileOrLevel ( backup ) )
TSystem : : removeFileOrLevel_throw ( backup ) ;
TSystem : : copyFileOrLevel_throw ( backup , path ) ;
} catch ( . . . ) {
}
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : save ( const TFilePath & fp , const TFilePath & oldFp , bool overwritePalette )
{
TFilePath dOldPath = ( ! oldFp . isEmpty ( ) ) ? oldFp : getScene ( ) - > decodeFilePath ( m_path ) ;
TFilePath dDstPath = getScene ( ) - > decodeFilePath ( fp ) ;
TSystem : : touchParentDir ( dDstPath ) ;
// backup
if ( Preferences : : instance ( ) - > isLevelsBackupEnabled ( ) & &
dOldPath = = dDstPath & &
TSystem : : doesExistFileOrLevel ( dDstPath ) )
saveBackup ( dDstPath ) ;
if ( isAreadOnlyLevel ( dDstPath ) ) {
if ( m_editableRange . empty ( ) & & ! m_temporaryHookMerged ) //file interaly locked
throw TSystemException ( dDstPath , " The level cannot be saved: it is a read only level. " ) ;
else if ( getType ( ) ! = OVL_XSHLEVEL ) {
//file partially unlocked
2016-04-19 19:32:17 +12:00
std : : wstring fileName = getEditableFileName ( ) ;
2016-03-19 06:57:51 +13:00
assert ( ! fileName . empty ( ) ) ;
TFilePath app = dDstPath . withName ( fileName ) . withType ( dDstPath . getType ( ) ) ;
//removes old files
if ( TSystem : : doesExistFileOrLevel ( app ) )
TSystem : : removeFileOrLevel ( app ) ;
TFilePathSet oldFilePaths ;
getFiles ( app , oldFilePaths ) ;
TFilePathSet : : iterator it ;
for ( it = oldFilePaths . begin ( ) ; it ! = oldFilePaths . end ( ) ; + + it ) {
if ( TSystem : : doesExistFileOrLevel ( * it ) )
TSystem : : removeFileOrLevel ( * it ) ;
}
// save new files
TXshSimpleLevel * sl = new TXshSimpleLevel ;
sl - > setScene ( getScene ( ) ) ;
sl - > setPalette ( getPalette ( ) ) ;
sl - > setPath ( getScene ( ) - > codeFilePath ( app ) ) ;
sl - > setType ( getType ( ) ) ;
2016-04-18 15:13:38 +12:00
std : : set < TFrameId > : : iterator eft , efEnd ;
2016-03-19 06:57:51 +13:00
for ( eft = m_editableRange . begin ( ) ; eft ! = efEnd ; + + eft ) {
const TFrameId & fid = * eft ;
sl - > setFrame ( fid , getFrame ( fid , false ) ) ;
}
// Copy hooks
HookSet * hookSet = sl - > getHookSet ( ) ;
* hookSet = * getHookSet ( ) ;
FramesSet : : iterator ft , fEnd = m_frames . end ( ) ;
for ( ft = m_frames . begin ( ) ; ft ! = fEnd ; + + ft ) {
const TFrameId & fid = * ft ;
if ( m_editableRange . find ( fid ) = = m_editableRange . end ( ) )
hookSet - > eraseFrame ( fid ) ;
}
// Copy mesh level
sl - > save ( app ) ;
2016-04-15 17:11:23 +12:00
# ifdef _WIN32
2016-03-19 06:57:51 +13:00
//hides files
oldFilePaths . clear ( ) ;
if ( TSystem : : doesExistFileOrLevel ( app ) )
TSystem : : hideFileOrLevel ( app ) ;
getFiles ( app , oldFilePaths ) ;
for ( it = oldFilePaths . begin ( ) ; it ! = oldFilePaths . end ( ) ; + + it ) {
if ( TSystem : : doesExistFileOrLevel ( * it ) )
TSystem : : hideFileOrLevel ( * it ) ;
}
# endif
return ;
}
}
if ( dOldPath ! = dDstPath & & m_path ! = TFilePath ( ) ) {
const TFilePath & dSrcPath = dOldPath ;
try {
if ( TSystem : : doesExistFileOrLevel ( dSrcPath ) ) {
if ( TSystem : : doesExistFileOrLevel ( dDstPath ) )
TSystem : : removeFileOrLevel ( dDstPath ) ;
copyFiles ( dDstPath , dSrcPath ) ;
}
} catch ( . . . ) {
}
}
//when saving the level palette with global name
if ( overwritePalette & & getType ( ) = = TZP_XSHLEVEL & & getPalette ( ) & & getPalette ( ) - > getGlobalName ( ) ! = L " " ) {
overwritePalette = false ;
TFilePath palettePath = dDstPath . withNoFrame ( ) . withType ( " tpl " ) ;
StudioPalette : : instance ( ) - > save ( palettePath , getPalette ( ) ) ;
}
saveSimpleLevel ( dDstPath , overwritePalette ) ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : saveSimpleLevel ( const TFilePath & decodedFp , bool overwritePalette )
{
/* Precondition: Destination level with path decodedFp is supposed to already
store those image frames not tagged as ' modified ' in this level
instance . */
TFilePath oldPath = m_path ;
TFilePath dOldPath = getScene ( ) - > decodeFilePath ( oldPath ) ;
// Substitute m_path with decodedFp until the function quits.
struct CopyOnExit {
TFilePath & m_dstPath , & m_srcPath ;
~ CopyOnExit ( ) { m_dstPath = m_srcPath ; }
} copyOnExit = { m_path = decodedFp , oldPath } ; // m_path substituted here until function quits
bool savingOriginal = ( decodedFp = = dOldPath ) ,
paletteNotSaved = false ;
int imFlags = savingOriginal ? ImageManager : : dontPutInCache | ImageManager : : toBeSaved : ImageManager : : dontPutInCache ;
std : : vector < TFrameId > fids ;
getFids ( fids ) ;
std : : vector < TFrameId > : : iterator it ;
bool isLevelModified = getProperties ( ) - > getDirtyFlag ( ) ;
bool isPaletteModified = false ;
if ( getPalette ( ) )
isPaletteModified = getPalette ( ) - > getDirtyFlag ( ) ;
if ( isLevelModified | | isPaletteModified ) {
// gmt (8/8/08. provo a risolvere il pasticcio della scrittura dei tlv. Dobbiamo
// ripensarci con piu' calma. Per ora cerco di fare meno danno possibile).
TDimension oldRes ( 0 , 0 ) ;
if ( TSystem : : doesExistFileOrLevel ( decodedFp ) ) {
TLevelReaderP lr ( decodedFp ) ;
const TImageInfo * imageInfo = m_frames . empty ( ) ? lr - > getImageInfo ( ) : lr - > getImageInfo ( * ( m_frames . begin ( ) ) ) ;
if ( imageInfo ) {
oldRes . lx = imageInfo - > m_lx ;
oldRes . ly = imageInfo - > m_ly ;
lr = TLevelReaderP ( ) ;
if ( getProperties ( ) - > getImageRes ( ) ! = oldRes ) {
//Il comando canvas size cambia le dimensioni del livello!!!
//Se il file già esiste, nel level writer vengono risettate le dimesnioni del file esistente
//e salva male
TSystem : : removeFileOrLevel ( decodedFp ) ;
}
}
}
// overwrite tlv
if ( decodedFp . getType ( ) = = " tlv " & & TSystem : : doesExistFileOrLevel ( decodedFp ) ) {
if ( isLevelModified ) {
// in questo caso dovrei scrivere solo i frame modificati.
// certamente NON DEVO scrivere quelli che non ho (e che dovrei
// rileggere dallo stesso file che sto scrivendo
int oldSubs = getProperties ( ) - > getSubsampling ( ) ;
TLevelWriterP lw ;
try {
lw = TLevelWriterP ( decodedFp ) ;
} catch ( . . . ) {
//revert subsampling
m_properties - > setSubsampling ( oldSubs ) ;
m_path = oldPath ;
throw TSystemException ( decodedFp , " can't fopen. \n Someone may be saving the same file. Please wait a while and retry. " ) ;
}
lw - > setOverwritePaletteFlag ( overwritePalette ) ;
lw - > setCreator ( getCreatorString ( ) ) ;
lw - > setPalette ( getPalette ( ) ) ;
// Filter out of the renumber table all non-tlv frames (could happen if the level
// is a scan-cleanup mix). This is fine even on the temporarily substituted m_path.
std : : map < TFrameId , TFrameId > renumberTable ;
std : : map < TFrameId , TFrameId > : : reverse_iterator mapIt = m_renumberTable . rbegin ( ) ;
for ( mapIt ; mapIt ! = m_renumberTable . rend ( ) ; + + mapIt ) {
TFrameId id = mapIt - > first ;
if ( getFrameStatus ( id ) ! = Scanned & & getFrameStatus ( id ) ! = CleanupPreview )
renumberTable [ id ] = mapIt - > second ;
}
m_renumberTable . clear ( ) ;
m_renumberTable = renumberTable ;
lw - > setIconSize ( Preferences : : instance ( ) - > getIconSize ( ) ) ;
if ( ! isSubsequence ( ) )
lw - > renumberFids ( m_renumberTable ) ;
if ( getContentHistory ( ) )
lw - > setContentHistory ( getContentHistory ( ) - > clone ( ) ) ;
ImageLoader : : BuildExtData extData ( this , TFrameId ( ) ) ;
for ( it = fids . begin ( ) ; it ! = fids . end ( ) ; + + it ) {
2016-04-19 19:32:17 +12:00
std : : string imageId = getImageId ( * it , Normal ) ; // Retrieve the actual level frames ("L_whatever")
2016-03-19 06:57:51 +13:00
if ( ! ImageManager : : instance ( ) - > isModified ( imageId ) )
continue ;
extData . m_fid = * it ;
TImageP img = ImageManager : : instance ( ) - > getImage ( imageId , imFlags , & extData ) ;
assert ( img ) ;
if ( ! img )
continue ;
int subs = 1 ;
if ( TToonzImageP ti = img )
subs = ti - > getSubsampling ( ) ;
else if ( TRasterImageP ri = img )
subs = ri - > getSubsampling ( ) ;
assert ( subs = = 1 ) ;
if ( subs ! = 1 )
continue ;
if ( TToonzImageP ti = img ) {
/*- SaveBoxを塗り漏れ防止に使用している場合、実際の画像範囲とSaveBoxのサイズが異なるため、ここで更新しておく-*/
TRect saveBox ;
TRop : : computeBBox ( ti - > getRaster ( ) , saveBox ) ;
ti - > setSavebox ( saveBox ) ;
}
lw - > getFrameWriter ( * it ) - > save ( img ) ;
}
lw = TLevelWriterP ( ) ; // TLevelWriterP's destructor saves the palette
} else if ( isPaletteModified & & overwritePalette ) {
TFilePath palettePath = decodedFp . withNoFrame ( ) . withType ( " tpl " ) ;
if ( Preferences : : instance ( ) - > isLevelsBackupEnabled ( ) & & TSystem : : doesExistFileOrLevel ( palettePath ) )
saveBackup ( palettePath ) ;
TOStream os ( palettePath ) ;
if ( os . checkStatus ( ) )
os < < getPalette ( ) ;
else
paletteNotSaved = true ;
}
} else {
// per ora faccio quello che facevo prima, ma dobbiamo rivedere tutta la strategia
LevelUpdater updater ( this ) ;
updater . getLevelWriter ( ) - > setCreator ( getCreatorString ( ) ) ;
if ( isLevelModified ) {
// Apply the level's renumber table, before saving other files.
// NOTE: This is currently NOT under LevelUpdater's responsibility, as renumber tables
// are set/manipulated heavily here. The approach should be re-designed, though...
updater . getLevelWriter ( ) - > renumberFids ( m_renumberTable ) ;
if ( ! m_editableRange . empty ( ) )
2016-04-19 19:32:17 +12:00
fids = std : : vector < TFrameId > ( m_editableRange . begin ( ) , m_editableRange . end ( ) ) ;
2016-03-19 06:57:51 +13:00
ImageLoader : : BuildExtData extData ( this , TFrameId ( ) ) ;
for ( it = fids . begin ( ) ; it ! = fids . end ( ) ; + + it ) {
2016-04-19 19:32:17 +12:00
std : : string imageId = getImageId ( * it , Normal ) ; // Retrieve the actual level frames ("L_whatever")
2016-03-19 06:57:51 +13:00
if ( ! ImageManager : : instance ( ) - > isModified ( imageId ) )
continue ;
extData . m_fid = * it ;
TImageP img = ImageManager : : instance ( ) - > getImage ( imageId , imFlags , & extData ) ;
assert ( img ) ;
if ( ! img )
continue ;
int subs = 1 ;
if ( TToonzImageP ti = img )
subs = ti - > getSubsampling ( ) ;
else if ( TRasterImageP ri = img )
subs = ri - > getSubsampling ( ) ;
assert ( subs = = 1 ) ;
if ( subs ! = 1 )
continue ;
updater . update ( * it , img ) ;
}
}
updater . close ( ) ; //Needs the original level subs
if ( ( getType ( ) & FULLCOLOR_TYPE ) & & isPaletteModified )
FullColorPalette : : instance ( ) - > savePalette ( getScene ( ) ) ;
}
}
// Save hooks
TFilePath hookFile ;
HookSet * hookSet = 0 ;
// Save the hookSet in a temporary hook file
if ( getType ( ) = = OVL_XSHLEVEL & & ! m_editableRange . empty ( ) ) {
hookSet = new HookSet ( * getHookSet ( ) ) ;
FramesSet : : const_iterator it ;
for ( it = m_frames . begin ( ) ; it ! = m_frames . end ( ) ; + + it ) {
TFrameId fid = * it ;
if ( m_editableRange . find ( fid ) = = m_editableRange . end ( ) )
hookSet - > eraseFrame ( fid ) ;
}
//file partially unlocked
2016-04-19 19:32:17 +12:00
std : : wstring fileName = getEditableFileName ( ) ;
2016-03-19 06:57:51 +13:00
assert ( ! fileName . empty ( ) ) ;
TFilePath app = decodedFp . withName ( fileName ) . withType ( decodedFp . getType ( ) ) ;
hookFile = getHookPath ( app ) ;
} else {
hookFile = getHookPath ( decodedFp ) ;
hookSet = getHookSet ( ) ;
}
2016-04-15 17:11:23 +12:00
# ifdef _WIN32
2016-03-19 06:57:51 +13:00
// Remove the hidden attribute (since TOStream's fopen fails on hidden files)
if ( getType ( ) = = OVL_XSHLEVEL & & ! m_editableRange . empty ( ) )
SetFileAttributesW ( hookFile . getWideString ( ) . c_str ( ) , FILE_ATTRIBUTE_NORMAL ) ;
# endif
if ( hookSet & & hookSet - > getHookCount ( ) > 0 ) {
TOStream os ( hookFile ) ;
os . openChild ( " hooks " ) ;
hookSet - > saveData ( os ) ;
os . closeChild ( ) ;
} else if ( TFileStatus ( hookFile ) . doesExist ( ) ) {
try {
TSystem : : deleteFile ( hookFile ) ;
} catch ( . . . ) {
}
}
2016-04-15 17:11:23 +12:00
# ifdef _WIN32
2016-03-19 06:57:51 +13:00
if ( getType ( ) = = OVL_XSHLEVEL & & ! m_editableRange . empty ( ) )
TSystem : : hideFileOrLevel ( hookFile ) ;
# endif
if ( savingOriginal ) {
setRenumberTable ( ) ; // Since the renumber table refers to the
// 'original' frames saved on disk
if ( m_properties )
m_properties - > setDirtyFlag ( false ) ;
if ( getPalette ( ) & & overwritePalette )
getPalette ( ) - > setDirtyFlag ( false ) ;
}
if ( paletteNotSaved )
throw TSystemException ( m_path , " The palette of the level could not be saved. " ) ;
}
//-----------------------------------------------------------------------------
std : : string TXshSimpleLevel : : getImageId ( const TFrameId & fid , int frameStatus ) const
{
if ( frameStatus < 0 )
frameStatus = getFrameStatus ( fid ) ;
2016-04-19 19:32:17 +12:00
std : : string prefix = " L " ;
2016-03-19 06:57:51 +13:00
if ( frameStatus & CleanupPreview )
prefix = " P " ;
else if ( ( frameStatus & ( Scanned | Cleanupped ) ) = = Scanned )
prefix = " S " ;
2016-04-19 19:32:17 +12:00
std : : string imageId = m_idBase + " _ " + prefix + fid . expand ( ) ;
2016-03-19 06:57:51 +13:00
return imageId ;
}
//-----------------------------------------------------------------------------
int TXshSimpleLevel : : getFrameStatus ( const TFrameId & fid ) const
{
std : : map < TFrameId , int > : : const_iterator it = m_framesStatus . find ( fid ) ;
return ( it ! = m_framesStatus . end ( ) ) ? it - > second : Normal ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : setFrameStatus ( const TFrameId & fid , int status )
{
assert ( ( status & ~ ( Scanned | Cleanupped | CleanupPreview ) ) = = 0 ) ;
m_framesStatus [ fid ] = status ;
}
//-----------------------------------------------------------------------------
/*- CleanupPopup::setCurrentLevel / TCleanupper で使用 -*/
void TXshSimpleLevel : : makeTlv ( const TFilePath & tlvPath )
{
int ltype = getType ( ) ;
if ( ! ( ltype & FULLCOLOR_TYPE ) ) {
assert ( ltype & FULLCOLOR_TYPE ) ;
return ;
}
setType ( TZP_XSHLEVEL ) ;
m_scannedPath = m_path ;
assert ( tlvPath . getType ( ) = = " tlv " ) ;
m_path = tlvPath ;
FramesSet : : const_iterator it ;
for ( it = m_frames . begin ( ) ; it ! = m_frames . end ( ) ; + + it ) {
TFrameId fid = * it ;
setFrameStatus ( fid , Scanned ) ;
ImageManager : : instance ( ) - > rebind ( getImageId ( fid , Scanned ) , getImageId ( fid , 0 ) ) ;
ImageManager : : instance ( ) - > rebind ( getIconId ( fid , Scanned ) , getIconId ( fid , 0 ) ) ;
}
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : invalidateFrames ( )
{
FramesSet : : iterator ft , fEnd = m_frames . end ( ) ;
for ( ft = m_frames . begin ( ) ; ft ! = fEnd ; + + ft )
ImageManager : : instance ( ) - > invalidate ( getImageId ( * ft ) ) ;
}
//-----------------------------------------------------------------------------
/*- 指定したFIdのみInvalidateする -*/
void TXshSimpleLevel : : invalidateFrame ( const TFrameId & fid )
{
2016-04-19 19:32:17 +12:00
std : : string id = getImageId ( fid ) ;
2016-03-19 06:57:51 +13:00
ImageManager : : instance ( ) - > invalidate ( id ) ;
}
//-----------------------------------------------------------------------------
// crea un frame con tipo, dimensioni, dpi, ecc. compatibili con il livello
TImageP TXshSimpleLevel : : createEmptyFrame ( )
{
TImageP result ;
switch ( m_type ) {
case PLI_XSHLEVEL :
result = new TVectorImage ;
CASE MESH_XSHLEVEL : assert ( false ) ; // Not implemented yet
DEFAULT : {
// normally the image must have the level->getProperties()->getImageDpi().
// if this value is missing (for some reason - can this happen, ever?) then
// we use the getDpi() (that is the current dpi, e.g. cameraDpi or customDpi).
TPointD dpi = getProperties ( ) - > getImageDpi ( ) ;
/*--
tgaからtlvにconvertしたものをInsert Pasteしたとき 、
ペ ー ス ト し た フ レ ー ム に の み DPIが付いてしまうので 、 こ の 処 理 は 省 く
- - */
//if(dpi.x==0.0 || dpi.y==0.0)
// dpi = getProperties()->getDpi();
TDimension res = getProperties ( ) - > getImageRes ( ) ;
if ( m_type = = TZP_XSHLEVEL ) {
TRasterCM32P raster ( res ) ;
raster - > fill ( TPixelCM32 ( ) ) ;
TToonzImageP ti ( raster , TRect ( ) ) ;
ti - > setDpi ( dpi . x , dpi . y ) ;
ti - > setSavebox ( TRect ( 0 , 0 , res . lx - 1 , res . ly - 1 ) ) ;
result = ti ;
} else {
TRaster32P raster ( res ) ;
raster - > fill ( TPixel32 ( 0 , 0 , 0 , 0 ) ) ;
TRasterImageP ri ( raster ) ;
ri - > setDpi ( dpi . x , dpi . y ) ;
result = ri ;
}
}
}
return result ;
}
//-----------------------------------------------------------------------------
// ritorna la risoluzione dei frames del livello (se il livello non e' vettoriale)
TDimension TXshSimpleLevel : : getResolution ( )
{
if ( isEmpty ( ) | | getType ( ) = = PLI_XSHLEVEL )
return TDimension ( ) ;
return m_properties - > getImageRes ( ) ;
}
//-----------------------------------------------------------------------------
// ritorna il dpi letto da file
TPointD TXshSimpleLevel : : getImageDpi ( const TFrameId & fid , int frameStatus )
{
if ( isEmpty ( ) | | getType ( ) = = PLI_XSHLEVEL )
return TPointD ( ) ;
const TFrameId & theFid = ( fid = = TFrameId : : NO_FRAME | | ! isFid ( fid ) ) ? getFirstFid ( ) : fid ;
2016-04-19 19:32:17 +12:00
const std : : string & imageId = getImageId ( theFid , frameStatus ) ;
2016-03-19 06:57:51 +13:00
const TImageInfo * imageInfo = ImageManager : : instance ( ) - > getInfo ( imageId , ImageManager : : none , 0 ) ;
if ( ! imageInfo )
return TPointD ( ) ;
return TPointD ( imageInfo - > m_dpix , imageInfo - > m_dpiy ) ;
}
//-----------------------------------------------------------------------------
int TXshSimpleLevel : : getImageSubsampling ( const TFrameId & fid ) const
{
if ( isEmpty ( ) | | getType ( ) = = PLI_XSHLEVEL )
return 1 ;
TImageP img = TImageCache : : instance ( ) - > get ( getImageId ( fid ) , false ) ;
if ( ! img )
return 1 ;
if ( TRasterImageP ri = img )
return ri - > getSubsampling ( ) ;
if ( TToonzImageP ti = img )
return ti - > getSubsampling ( ) ;
return 1 ;
}
//-----------------------------------------------------------------------------
// ritorna il dpi corrente del livello
TPointD TXshSimpleLevel : : getDpi ( const TFrameId & fid , int frameStatus )
{
TPointD dpi ;
if ( m_properties - > getDpiPolicy ( ) = = LevelProperties : : DP_ImageDpi )
dpi = getImageDpi ( fid , frameStatus ) ;
else
dpi = m_properties - > getDpi ( ) ;
return dpi ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : renumber ( const std : : vector < TFrameId > & fids )
{
assert ( fids . size ( ) = = m_frames . size ( ) ) ;
int n = fids . size ( ) ;
int i = 0 ;
std : : vector < TFrameId > oldFids ;
getFids ( oldFids ) ;
std : : map < TFrameId , TFrameId > table ;
std : : map < TFrameId , TFrameId > newRenumberTable ;
for ( std : : vector < TFrameId > : : iterator it = oldFids . begin ( ) ; it ! = oldFids . end ( ) ; + + it ) {
TFrameId oldFrameId = * it ;
TFrameId newFrameId = fids [ i + + ] ;
table [ oldFrameId ] = newFrameId ;
std : : map < TFrameId , TFrameId > : : iterator mapIt = m_renumberTable . begin ( ) ;
for ( mapIt ; mapIt ! = m_renumberTable . end ( ) ; + + mapIt )
if ( mapIt - > second = = oldFrameId ) {
newRenumberTable [ mapIt - > first ] = newFrameId ;
break ;
}
}
std : : map < TFrameId , TFrameId > : : iterator newMapIt = newRenumberTable . begin ( ) ;
for ( newMapIt ; newMapIt ! = newRenumberTable . end ( ) ; + + newMapIt )
m_renumberTable [ newMapIt - > first ] = newMapIt - > second ;
m_frames . clear ( ) ;
for ( i = 0 ; i < n ; + + i ) {
TFrameId fid ( fids [ i ] ) ;
assert ( m_frames . count ( fid ) = = 0 ) ;
m_frames . insert ( fid ) ;
}
ImageManager * im = ImageManager : : instance ( ) ;
std : : map < TFrameId , TFrameId > : : iterator jt ;
{
for ( i = 0 , jt = table . begin ( ) ; jt ! = table . end ( ) ; + + jt , + + i )
im - > rebind ( getImageId ( jt - > first ) , " ^ " + toString ( i ) ) ;
for ( i = 0 , jt = table . begin ( ) ; jt ! = table . end ( ) ; + + jt , + + i )
im - > rebind ( " ^ " + toString ( i ) , getImageId ( jt - > second ) ) ;
}
if ( getType ( ) = = PLI_XSHLEVEL ) {
for ( i = 0 , jt = table . begin ( ) ; jt ! = table . end ( ) ; + + jt , + + i ) {
const std : : string & id = rasterized ( getImageId ( jt - > first ) ) ;
if ( im - > isBound ( id ) )
im - > rebind ( id , rasterized ( " ^ " + toString ( i ) ) ) ;
}
for ( i = 0 , jt = table . begin ( ) ; jt ! = table . end ( ) ; + + jt , + + i ) {
const std : : string & id = rasterized ( " ^ " + toString ( i ) ) ;
if ( im - > isBound ( id ) )
im - > rebind ( id , rasterized ( getImageId ( jt - > second ) ) ) ;
}
}
if ( getType ( ) & FULLCOLOR_TYPE ) {
for ( i = 0 , jt = table . begin ( ) ; jt ! = table . end ( ) ; + + jt , + + i ) {
const std : : string & id = filled ( getImageId ( jt - > first ) ) ;
if ( im - > isBound ( id ) )
im - > rebind ( id , filled ( " ^ " + toString ( i ) ) ) ;
}
for ( i = 0 , jt = table . begin ( ) ; jt ! = table . end ( ) ; + + jt , + + i ) {
const std : : string & id = filled ( " ^ " + toString ( i ) ) ;
if ( im - > isBound ( id ) )
im - > rebind ( id , filled ( getImageId ( jt - > second ) ) ) ;
}
}
m_properties - > setDirtyFlag ( true ) ;
if ( getHookSet ( ) )
getHookSet ( ) - > renumber ( table ) ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : copyFiles ( const TFilePath & dst , const TFilePath & src )
{
if ( dst = = src )
return ;
TSystem : : touchParentDir ( dst ) ;
TSystem : : copyFileOrLevel_throw ( dst , src ) ;
if ( dst . getType ( ) = = " tlv " ) {
//Copio la palette del livello
TFilePath srcPltPath = src . getParentDir ( ) + TFilePath ( src . getWideName ( ) + L " .tpl " ) ;
if ( TFileStatus ( srcPltPath ) . doesExist ( ) )
TSystem : : copyFile ( dst . getParentDir ( ) + TFilePath ( dst . getWideName ( ) + L " .tpl " ) , srcPltPath , true ) ;
}
if ( dst . getType ( ) = = " tzp " | | dst . getType ( ) = = " tzu " ) {
//Copio la palette del livello
TFilePath srcPltPath = src . getParentDir ( ) + TFilePath ( src . getWideName ( ) + L " .plt " ) ;
if ( TFileStatus ( srcPltPath ) . doesExist ( ) )
TSystem : : copyFile ( dst . getParentDir ( ) + TFilePath ( dst . getWideName ( ) + L " .plt " ) , srcPltPath , true ) ;
}
const TFilePath & srcHookFile = TXshSimpleLevel : : getExistingHookFile ( src ) ;
if ( ! srcHookFile . isEmpty ( ) ) {
const TFilePath & dstHookFile = getHookPath ( dst ) ;
TSystem : : copyFile ( dstHookFile , srcHookFile , true ) ;
}
TFilePath files = src . getParentDir ( ) + ( src . getName ( ) + " _files " ) ;
if ( TFileStatus ( files ) . doesExist ( ) & & TFileStatus ( files ) . isDirectory ( ) )
TSystem : : copyDir ( dst . getParentDir ( ) + ( src . getName ( ) + " _files " ) , files ) ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : renameFiles ( const TFilePath & dst , const TFilePath & src )
{
if ( dst = = src )
return ;
TSystem : : touchParentDir ( dst ) ;
if ( TSystem : : doesExistFileOrLevel ( dst ) )
TXshSimpleLevel : : removeFiles ( dst ) ;
TSystem : : renameFileOrLevel_throw ( dst , src ) ;
if ( dst . getType ( ) = = " tlv " )
TSystem : : renameFile ( dst . withType ( " tpl " ) , src . withType ( " tpl " ) ) ;
const TFilePath & srcHookFile = TXshSimpleLevel : : getExistingHookFile ( src ) ;
if ( ! srcHookFile . isEmpty ( ) ) {
const TFilePath & dstHookFile = getHookPath ( dst ) ;
TSystem : : renameFile ( dstHookFile , srcHookFile ) ;
}
TFilePath files = src . getParentDir ( ) + ( src . getName ( ) + " _files " ) ;
if ( TFileStatus ( files ) . doesExist ( ) & & TFileStatus ( files ) . isDirectory ( ) )
TSystem : : renameFile ( dst . getParentDir ( ) + ( dst . getName ( ) + " _files " ) , files ) ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : removeFiles ( const TFilePath & fp )
{
TSystem : : moveFileOrLevelToRecycleBin ( fp ) ;
if ( fp . getType ( ) = = " tlv " ) {
TFilePath tpl = fp . withType ( " tpl " ) ;
if ( TFileStatus ( tpl ) . doesExist ( ) )
TSystem : : moveFileToRecycleBin ( tpl ) ;
}
// Delete ALL hook files (ie from every Toonz version)
const QStringList & hookFiles = TXshSimpleLevel : : getHookFiles ( fp ) ;
int f , fCount = hookFiles . size ( ) ;
for ( f = 0 ; f ! = fCount ; + + f )
TSystem : : moveFileToRecycleBin ( TFilePath ( hookFiles [ f ] . toStdWString ( ) ) ) ;
TFilePath files = fp . getParentDir ( ) + ( fp . getName ( ) + " _files " ) ;
if ( TFileStatus ( files ) . doesExist ( ) & & TFileStatus ( files ) . isDirectory ( ) )
TSystem : : rmDirTree ( files ) ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : getFiles ( const TFilePath & fp , TFilePathSet & fpset )
{
if ( fp . getType ( ) = = " tlv " ) {
TFilePath tpl = fp . withType ( " tpl " ) ;
if ( TFileStatus ( tpl ) . doesExist ( ) )
fpset . push_back ( tpl ) ;
}
// Store the hooks file if any (NOTE: there could be more than one hooks
// file. I'm retaining the behavior I've seen, but was this really intended?
// Shouldn't we return ALL the hooks files?)
const TFilePath & hookFile = getExistingHookFile ( fp ) ;
if ( ! hookFile . isEmpty ( ) )
fpset . push_back ( hookFile ) ;
// Needed for TAB Manga & Kids and not used in Toonz
//TFilePath files = fp.getParentDir() + (fp.getName() + "_files");
//if(TFileStatus(files).doesExist() && TFileStatus(files).isDirectory())
// TSystem::rmDirTree(files);
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : setContentHistory ( TContentHistory * contentHistory )
{
if ( contentHistory ! = m_contentHistory . get ( ) )
m_contentHistory . reset ( contentHistory ) ;
}
//-----------------------------------------------------------------------------
void TXshSimpleLevel : : setCompatibilityMasks ( int writeMask , int neededMask , int forbiddenMask )
{
compatibility . writeMask = writeMask ;
compatibility . neededMask = neededMask ;
compatibility . forbiddenMask = forbiddenMask ;
}
//-----------------------------------------------------------------------------
TFilePath TXshSimpleLevel : : getHookPath ( const TFilePath & path )
{
// Translates: levelName..ext into levelName_hooks..ext.xml
// levelName.ext into levelName_hooks.ext.xml
// Observe that retaining the original level extension IS IMPORTANT, as it ensures
// the UNICITY of the association between a level path and its hook path (ie
// levels test..png and test..tif have separate hook files).
return TFilePath ( path . withName ( path . getName ( ) + " _hooks " ) . getWideString ( ) + L " .xml " ) ;
}
//-----------------------------------------------------------------------------
QStringList TXshSimpleLevel : : getHookFiles ( const TFilePath & decodedLevelPath )
{
const TFilePath & dirPath = decodedLevelPath . getParentDir ( ) ;
QDir levelDir ( QString : : fromStdWString ( dirPath . getWideString ( ) ) ) ;
QStringList hookFileFilter ( QString : : fromStdWString ( // We have to scan for files of the
decodedLevelPath . getWideName ( ) + L " _hooks*.xml " ) ) ; // form levelName_hooks*.xml to
// retain backward compatibility
return levelDir . entryList ( //
hookFileFilter , QDir : : Files | QDir : : NoDotAndDotDot , // Observe that we cleverly sort by
QDir : : Time ) ; // mod date :)
}
//-----------------------------------------------------------------------------
TFilePath TXshSimpleLevel : : getExistingHookFile ( const TFilePath & decodedLevelPath )
{
static const int pCount = 3 ;
static const QRegExp pattern [ pCount ] = {
// Prioritized in this order
QRegExp ( " .* \\ . \\ .?.+ \\ .xml$ " ) , // whatever.(.)ext.xml
QRegExp ( " .* \\ .xml$ " ) , // whatever.xml
QRegExp ( " .* \\ . \\ .?xml$ " ) // whatever.(.)xml
} ;
struct locals {
static inline int getPattern ( const QString & fp )
{
for ( int p = 0 ; p ! = pCount ; + + p )
if ( pattern [ p ] . exactMatch ( fp ) )
return p ;
return - 1 ;
}
} ; // locals
const QStringList & hookFiles = getHookFiles ( decodedLevelPath ) ;
if ( hookFiles . empty ( ) )
return TFilePath ( ) ;
// Return the hook file with the most recent (smallest) identified
// regexp pattern
int fPattern , p = pCount , h = - 1 ;
int f , fCount = hookFiles . size ( ) ;
for ( f = 0 ; f ! = fCount ; + + f ) {
fPattern = locals : : getPattern ( hookFiles [ f ] ) ;
if ( fPattern < p )
p = fPattern , h = f ;
}
assert ( h > = 0 ) ;
return ( h < 0 ) ? TFilePath ( ) : decodedLevelPath . getParentDir ( ) + TFilePath ( hookFiles [ h ] . toStdWString ( ) ) ;
}
//-----------------------------------------------------------------------------
TRectD TXshSimpleLevel : : getBBox ( const TFrameId & fid ) const
{
TRectD bbox ;
double dpiX = Stage : : inch , dpiY = dpiX ;
// Get the frame bbox in image coordinates
switch ( getType ( ) ) {
case PLI_XSHLEVEL :
case MESH_XSHLEVEL : {
// Load the image and extract its bbox forcibly
TImageP img = getFrame ( fid , false ) ;
if ( ! img )
return TRectD ( ) ;
bbox = img - > getBBox ( ) ;
if ( TMeshImageP mi = img )
mi - > getDpi ( dpiX , dpiY ) ;
}
DEFAULT : {
// Raster case: retrieve the image info from the ImageManager
const std : : string & imageId = getImageId ( fid ) ;
const TImageInfo * info = ImageManager : : instance ( ) - > getInfo ( imageId , ImageManager : : none , 0 ) ;
if ( ! info )
return TRectD ( ) ;
bbox =
TRectD ( TPointD ( info - > m_x0 , info - > m_y0 ) , TDimensionD ( info - > m_lx , info - > m_ly ) ) - // Using lx, ly is less ambiguous
0.5 * TPointD ( info - > m_lx , info - > m_ly ) ;
if ( info - > m_dpix > 0.0 & & info - > m_dpiy > 0.0 )
dpiX = info - > m_dpix , dpiY = info - > m_dpiy ;
}
}
// Get the frame's dpi and traduce the bbox to inch coordinates
return TScale ( 1.0 / dpiX , 1.0 / dpiY ) * bbox ;
}