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