|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// TnzCore includes
|
|
Toshihiro Shimizu |
890ddd |
#include "tsystem.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "trasterimage.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tiio.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "timageinfo.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tcontenthistory.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/toonzscene.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/levelproperties.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/preferences.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/sceneproperties.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/levelupdater.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//*****************************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// Local namespace stuff
|
|
Toshihiro Shimizu |
890ddd |
//*****************************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
namespace {
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
inline bool supportsRandomAccess(const TFilePath &fp) {
|
|
Shinya Kitaoka |
120a6e |
const std::string &type = fp.getType();
|
|
Shinya Kitaoka |
120a6e |
return type == "tlv" || // TLVs do support random access
|
|
Shinya Kitaoka |
120a6e |
// type == "pli" || // PLIs... I
|
|
Shinya Kitaoka |
120a6e |
// thought they would - but no :(
|
|
Shinya Kitaoka |
120a6e |
// type == "mov" || // MOVs are
|
|
Shinya Kitaoka |
120a6e |
// 'on the way' to support it... for now, no
|
|
Shinya Kitaoka |
120a6e |
fp.getDots() == ".."; // Multi-file levels of course do
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void enforceBpp(TPropertyGroup *pg, int bpp, bool upgradeOnly) {
|
|
Shinya Kitaoka |
120a6e |
// Most properties have a "Bits Per Pixel" property. Enforce the M there in
|
|
Shinya Kitaoka |
120a6e |
// case.
|
|
Shinya Kitaoka |
120a6e |
TEnumProperty *bppProp = (TEnumProperty *)pg->getProperty("Bits Per Pixel");
|
|
Shinya Kitaoka |
120a6e |
if (bppProp) {
|
|
Shinya Kitaoka |
120a6e |
typedef TEnumProperty::Range Range;
|
|
Shinya Kitaoka |
120a6e |
const Range &range = bppProp->getRange();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Retrieve current index
|
|
Shinya Kitaoka |
120a6e |
int idx = bppProp->getIndex();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Search for a suitable 32-bit or 64-bit value
|
|
Shinya Kitaoka |
120a6e |
int currentBpp = upgradeOnly ? std::stoi(bppProp->getValueAsString()) : 0;
|
|
Shinya Kitaoka |
120a6e |
int targetBpp = (std::numeric_limits<int>::max)(), targetIdx = -1;</int>
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int i, count = (int)range.size();
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < count; ++i) {
|
|
Shinya Kitaoka |
120a6e |
int bppEntry = std::stoi(range[i]);
|
|
Shinya Kitaoka |
120a6e |
if ((bppEntry % bpp == 0) && currentBpp <= bppEntry &&
|
|
Shinya Kitaoka |
120a6e |
bppEntry < targetBpp)
|
|
Shinya Kitaoka |
120a6e |
targetBpp = bppEntry, targetIdx = i;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (targetIdx >= 0) bppProp->setIndex(targetIdx);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Some properties have an "Alpha Channel" TBoolProperty (PNGs, currently). In
|
|
Shinya Kitaoka |
120a6e |
// case, check that.
|
|
Shinya Kitaoka |
120a6e |
if (bpp % 32 == 0) {
|
|
Shinya Kitaoka |
120a6e |
TBoolProperty *alphaProp =
|
|
Shinya Kitaoka |
120a6e |
(TBoolProperty *)pg->getProperty("Alpha Channel");
|
|
Shinya Kitaoka |
120a6e |
if (alphaProp) alphaProp->setValue(true);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
} // namespace
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//*****************************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// LevelUpdater implementation
|
|
Toshihiro Shimizu |
890ddd |
//*****************************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
LevelUpdater::LevelUpdater()
|
|
Shinya Kitaoka |
120a6e |
: m_pg(0)
|
|
Shinya Kitaoka |
120a6e |
, m_inputLevel(0)
|
|
Shinya Kitaoka |
120a6e |
, m_currIdx(0)
|
|
Shinya Kitaoka |
120a6e |
, m_imageInfo(0)
|
|
Shinya Kitaoka |
120a6e |
, m_usingTemporaryFile(false)
|
|
Shinya Kitaoka |
120a6e |
, m_opened(false) {}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
LevelUpdater::LevelUpdater(TXshSimpleLevel *sl)
|
|
Shinya Kitaoka |
120a6e |
: m_pg(0)
|
|
Shinya Kitaoka |
120a6e |
, m_inputLevel(0)
|
|
Shinya Kitaoka |
120a6e |
, m_imageInfo(0)
|
|
Shinya Kitaoka |
120a6e |
, m_currIdx(0)
|
|
Shinya Kitaoka |
120a6e |
, m_opened(false)
|
|
Shinya Kitaoka |
120a6e |
, m_usingTemporaryFile(false) {
|
|
Shinya Kitaoka |
120a6e |
open(sl);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
LevelUpdater::LevelUpdater(const TFilePath &fp, TPropertyGroup *lwProperties)
|
|
Shinya Kitaoka |
120a6e |
: m_pg(0)
|
|
Shinya Kitaoka |
120a6e |
, m_inputLevel(0)
|
|
Shinya Kitaoka |
120a6e |
, m_imageInfo(0)
|
|
Shinya Kitaoka |
120a6e |
, m_currIdx(0)
|
|
Shinya Kitaoka |
120a6e |
, m_opened(false)
|
|
Shinya Kitaoka |
120a6e |
, m_usingTemporaryFile(false) {
|
|
Shinya Kitaoka |
120a6e |
open(fp, lwProperties);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
LevelUpdater::~LevelUpdater() {
|
|
Shinya Kitaoka |
120a6e |
// Please, observe that the try-catch below here is NOT OPTIONAL.
|
|
Shinya Kitaoka |
120a6e |
// IT IS AN ERROR TO THROW INSIDE A DESTRUCTOR. EVER.
|
|
Shinya Kitaoka |
120a6e |
// Doing so damages the stack unwinding process - namely, it interferes
|
|
Shinya Kitaoka |
120a6e |
// with the destruction of OTHER objects going out of scope.
|
|
Shinya Kitaoka |
120a6e |
// C++ does NOT react well to that (ie could terminate() the process).
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
try {
|
|
Shinya Kitaoka |
120a6e |
close();
|
|
Shinya Kitaoka |
120a6e |
} catch (...) {
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void LevelUpdater::reset() {
|
|
Shinya Kitaoka |
120a6e |
m_lw = TLevelWriterP();
|
|
Shinya Kitaoka |
120a6e |
m_lwPath = TFilePath();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_lr = TLevelReaderP();
|
|
Shinya Kitaoka |
120a6e |
m_inputLevel = TLevelP();
|
|
Shinya Kitaoka |
120a6e |
m_sl = TXshSimpleLevelP();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
delete m_pg;
|
|
Shinya Kitaoka |
120a6e |
m_pg = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (m_imageInfo) {
|
|
Shinya Kitaoka |
120a6e |
delete m_imageInfo->m_properties;
|
|
Shinya Kitaoka |
120a6e |
delete m_imageInfo;
|
|
Shinya Kitaoka |
120a6e |
m_imageInfo = 0;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_fids.clear();
|
|
Shinya Kitaoka |
120a6e |
m_currIdx = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_usingTemporaryFile = false;
|
|
Shinya Kitaoka |
120a6e |
m_opened = false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void LevelUpdater::buildSourceInfo(const TFilePath &fp) {
|
|
Shinya Kitaoka |
120a6e |
try {
|
|
Shinya Kitaoka |
120a6e |
m_lr = TLevelReaderP(fp);
|
|
Shinya Kitaoka |
120a6e |
assert(m_lr);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
m_lr->enableRandomAccessRead(
|
|
Shinya Kitaoka |
120a6e |
true); // Movie files are intended with a constant fps
|
|
Shinya Kitaoka |
120a6e |
// should be made the default... TODO!
|
|
Shinya Kitaoka |
120a6e |
m_inputLevel = m_lr->loadInfo();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
const TImageInfo *info = m_lr->getImageInfo();
|
|
Shinya Kitaoka |
120a6e |
if (info) {
|
|
Shinya Kitaoka |
120a6e |
m_imageInfo = new TImageInfo(
|
|
Shinya Kitaoka |
120a6e |
*info); // Clone the info. The originals are owned by the reader.
|
|
Shinya Kitaoka |
120a6e |
if (info->m_properties)
|
|
Shinya Kitaoka |
120a6e |
m_imageInfo->m_properties =
|
|
Shinya Kitaoka |
120a6e |
info->m_properties->clone(); // Same for these (unfortunately,
|
|
Shinya Kitaoka |
120a6e |
// TImageInfo is currently
|
|
Shinya Kitaoka |
120a6e |
// no more than a struct...)
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
} catch (...) {
|
|
Shinya Kitaoka |
120a6e |
// The level exists but could not be read.
|
|
Shinya Kitaoka |
120a6e |
// Allowing write to a surviving temporary in this case...
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
m_lr = TLevelReaderP();
|
|
Shinya Kitaoka |
120a6e |
m_inputLevel = TLevelP(0);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (m_imageInfo) {
|
|
Shinya Kitaoka |
120a6e |
delete m_imageInfo->m_properties;
|
|
Shinya Kitaoka |
120a6e |
delete m_imageInfo;
|
|
Shinya Kitaoka |
120a6e |
m_imageInfo = 0;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void LevelUpdater::buildProperties(const TFilePath &fp) {
|
|
Shinya Kitaoka |
120a6e |
// Ensure that at least the default properties for specified fp.getType()
|
|
Shinya Kitaoka |
120a6e |
// exist.
|
|
Shinya Kitaoka |
120a6e |
m_pg = (m_imageInfo && m_imageInfo->m_properties)
|
|
Shinya Kitaoka |
120a6e |
? m_imageInfo->m_properties->clone()
|
|
Shinya Kitaoka |
120a6e |
: Tiio::makeWriterProperties(fp.getType());
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!m_pg) {
|
|
Shinya Kitaoka |
120a6e |
// If no suitable pg could be found, the extension must be wrong. Reset and
|
|
Shinya Kitaoka |
120a6e |
// throw.
|
|
Shinya Kitaoka |
120a6e |
reset();
|
|
Shinya Kitaoka |
120a6e |
throw TException("Unrecognized file format");
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
assert(m_pg);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void LevelUpdater::open(const TFilePath &fp, TPropertyGroup *pg) {
|
|
Shinya Kitaoka |
120a6e |
assert(!m_lw);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Find out if a corresponding level already exists on disk - in that case,
|
|
Shinya Kitaoka |
120a6e |
// load it
|
|
Shinya Kitaoka |
120a6e |
bool existsLevel = TSystem::doesExistFileOrLevel(fp);
|
|
Shinya Kitaoka |
120a6e |
if (existsLevel)
|
|
Shinya Kitaoka |
120a6e |
buildSourceInfo(fp); // Could be !m_lr if level could not be read
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Build Output Properties if needed
|
|
Shinya Kitaoka |
120a6e |
if (pg)
|
|
Shinya Kitaoka |
120a6e |
m_pg = pg->clone();
|
|
Shinya Kitaoka |
120a6e |
else
|
|
Shinya Kitaoka |
120a6e |
buildProperties(fp); // Throws only if not even the default properties
|
|
Shinya Kitaoka |
120a6e |
// could be found - ie, bad file type
|
|
Shinya Kitaoka |
120a6e |
try {
|
|
Shinya Kitaoka |
120a6e |
// Decide whether the update procedure requires a temporary file for
|
|
Shinya Kitaoka |
120a6e |
// appending
|
|
Shinya Kitaoka |
120a6e |
m_usingTemporaryFile = existsLevel && !supportsRandomAccess(fp);
|
|
Shinya Kitaoka |
120a6e |
if (m_usingTemporaryFile) {
|
|
Shinya Kitaoka |
120a6e |
// The level requires a temporary to write frames to. Upon closing, the
|
|
Shinya Kitaoka |
120a6e |
// original level
|
|
Shinya Kitaoka |
120a6e |
// is deleted and the temporary takes its place. Note that m_lw takes
|
|
Shinya Kitaoka |
120a6e |
// ownership of the properties group.
|
|
Shinya Kitaoka |
120a6e |
m_lwPath = getNewTemporaryFilePath(fp);
|
|
Shinya Kitaoka |
120a6e |
m_lw = TLevelWriterP(m_lwPath, m_pg->clone());
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (m_inputLevel)
|
|
Shinya Kitaoka |
120a6e |
for (TLevel::Iterator it = m_inputLevel->begin();
|
|
Shinya Kitaoka |
120a6e |
it != m_inputLevel->end(); ++it)
|
|
Shinya Kitaoka |
120a6e |
m_fids.push_back(it->first);
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
m_lr =
|
|
Shinya Kitaoka |
120a6e |
TLevelReaderP(); // Release the reader. This is necessary since the
|
|
Shinya Kitaoka |
120a6e |
m_lw = TLevelWriterP(
|
|
Shinya Kitaoka |
120a6e |
fp, m_pg->clone()); // original file itself will be MODIFIED.
|
|
Shinya Kitaoka |
120a6e |
m_lwPath = fp;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
} catch (...) {
|
|
Shinya Kitaoka |
120a6e |
// In this case, TLevelWriterP(..) failed, that object was never contructed,
|
|
Shinya Kitaoka |
120a6e |
// the assignment m_lw never took place. And m_lw == 0.
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Reset state and rethrow
|
|
Shinya Kitaoka |
120a6e |
reset();
|
|
Shinya Kitaoka |
120a6e |
throw;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// In case the writer saves icons inside the output level (TLV case), set the
|
|
Shinya Kitaoka |
120a6e |
// associated icon size now
|
|
Shinya Kitaoka |
120a6e |
TDimension iconSize = Preferences::instance()->getIconSize();
|
|
Shinya Kitaoka |
120a6e |
assert(iconSize.lx > 0 && iconSize.ly > 0);
|
|
Shinya Kitaoka |
120a6e |
m_lw->setIconSize(iconSize);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
m_opened = true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void LevelUpdater::open(TXshSimpleLevel *sl) {
|
|
Shinya Kitaoka |
120a6e |
assert(!m_lw);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
assert(sl && sl->getScene());
|
|
Shinya Kitaoka |
120a6e |
m_sl = sl;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
const TFilePath &fp = sl->getScene()->decodeFilePath(sl->getPath());
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Find out if a corresponding level already exists on disk - in that case,
|
|
Shinya Kitaoka |
120a6e |
// load it
|
|
Shinya Kitaoka |
120a6e |
bool existsLevel = TSystem::doesExistFileOrLevel(fp);
|
|
Shinya Kitaoka |
120a6e |
if (existsLevel)
|
|
Shinya Kitaoka |
120a6e |
buildSourceInfo(fp); // Could be !m_lr if level could not be read
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Build Output Properties
|
|
Shinya Kitaoka |
120a6e |
buildProperties(fp); // May throw if not even the default properties could be
|
|
Shinya Kitaoka |
120a6e |
// retrieved
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// If there was no level on disk, or the level properties require the alpha
|
|
Shinya Kitaoka |
120a6e |
// channel, enforce the
|
|
Shinya Kitaoka |
120a6e |
// bpp accordingly on m_pg.
|
|
Shinya Kitaoka |
120a6e |
LevelProperties *levelProperties = sl->getProperties();
|
|
Shinya Kitaoka |
120a6e |
assert(levelProperties);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (levelProperties->hasAlpha() || !existsLevel) {
|
|
Shinya Kitaoka |
120a6e |
int bpp = levelProperties->hasAlpha()
|
|
Shinya Kitaoka |
120a6e |
? std::min(32, levelProperties->getBpp())
|
|
Shinya Kitaoka |
120a6e |
: levelProperties->getBpp();
|
|
Shinya Kitaoka |
120a6e |
enforceBpp(m_pg, bpp, existsLevel);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Should sl->getPalette() be enforced on m_lw too? It was not present in the
|
|
Shinya Kitaoka |
120a6e |
// old code...
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
try {
|
|
Shinya Kitaoka |
120a6e |
// Decide whether the update procedure requires a temporary file for
|
|
Shinya Kitaoka |
120a6e |
// appending
|
|
Shinya Kitaoka |
120a6e |
m_usingTemporaryFile = existsLevel && !supportsRandomAccess(fp);
|
|
Shinya Kitaoka |
120a6e |
if (m_usingTemporaryFile) {
|
|
Shinya Kitaoka |
120a6e |
// The level requires a temporary to write frames to. Upon closing, the
|
|
Shinya Kitaoka |
120a6e |
// original level
|
|
Shinya Kitaoka |
120a6e |
// is deleted and the temporary takes its place.
|
|
Shinya Kitaoka |
120a6e |
m_lwPath = getNewTemporaryFilePath(fp);
|
|
Shinya Kitaoka |
120a6e |
m_lw = TLevelWriterP(m_lwPath, m_pg->clone());
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
m_lr = TLevelReaderP(); // Release the reader
|
|
Shinya Kitaoka |
120a6e |
m_lw = TLevelWriterP(fp, m_pg->clone()); // Open for write the usual way
|
|
Shinya Kitaoka |
120a6e |
m_lwPath = fp;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
} catch (...) {
|
|
Shinya Kitaoka |
120a6e |
// Reset state and rethrow
|
|
Shinya Kitaoka |
120a6e |
reset();
|
|
Shinya Kitaoka |
120a6e |
throw;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Load the frames directly from sl
|
|
Shinya Kitaoka |
120a6e |
sl->getFids(m_fids);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// In case the writer saves icons inside the output level (TLV case), set the
|
|
Shinya Kitaoka |
120a6e |
// associated icon size now
|
|
Shinya Kitaoka |
120a6e |
TDimension iconSize = Preferences::instance()->getIconSize();
|
|
Shinya Kitaoka |
120a6e |
assert(iconSize.lx > 0 && iconSize.ly > 0);
|
|
Shinya Kitaoka |
120a6e |
m_lw->setIconSize(iconSize);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (sl->getContentHistory())
|
|
Shinya Kitaoka |
120a6e |
m_lw->setContentHistory(m_sl->getContentHistory()->clone());
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
m_opened = true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TFilePath LevelUpdater::getNewTemporaryFilePath(const TFilePath &fp) {
|
|
Shinya Kitaoka |
120a6e |
TFilePath fp2;
|
|
Shinya Kitaoka |
120a6e |
int count = 1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
for (;;) {
|
|
shun-iwasawa |
f8c030 |
// changed the temporary name as the previous naming (like
|
|
shun-iwasawa |
f8c030 |
// "filename__1.png") had been misteken as sequential images
|
|
shun-iwasawa |
f8c030 |
fp2 = fp.withName(fp.getWideName() + L"_ottmp" + std::to_wstring(count++));
|
|
Shinya Kitaoka |
120a6e |
if (!TSystem::doesExistFileOrLevel(fp2)) break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
return fp2;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void LevelUpdater::addFramesTo(int endIdx) {
|
|
Shinya Kitaoka |
120a6e |
if (m_sl) {
|
|
Shinya Kitaoka |
120a6e |
// The simple level case can be optimized since some level's images could
|
|
Shinya Kitaoka |
120a6e |
// already be present
|
|
Shinya Kitaoka |
120a6e |
// in memory. Images are accessed through the level itself.
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (; m_currIdx < endIdx; ++m_currIdx) {
|
|
Shinya Kitaoka |
120a6e |
TImageP img = m_sl->getFullsampledFrame(m_fids[m_currIdx],
|
|
Shinya Kitaoka |
120a6e |
ImageManager::dontPutInCache);
|
|
Shinya Kitaoka |
120a6e |
assert(img);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!img && m_lr) {
|
|
Shinya Kitaoka |
120a6e |
// This should actually never happen. ImageManager should already ensure
|
|
Shinya Kitaoka |
120a6e |
// that img exists.
|
|
Shinya Kitaoka |
120a6e |
// However, as last resort let's just look at the file too...
|
|
Shinya Kitaoka |
120a6e |
img = m_lr->getFrameReader(m_fids[m_currIdx])->load();
|
|
Shinya Kitaoka |
120a6e |
if (img) img->setPalette(m_sl->getPalette());
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (img) m_lw->getFrameWriter(m_fids[m_currIdx])->save(img);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
} else if (m_lr) {
|
|
Shinya Kitaoka |
120a6e |
// Otherwise, just look in the file directly
|
|
Shinya Kitaoka |
120a6e |
for (; m_currIdx < endIdx; ++m_currIdx) {
|
|
Shinya Kitaoka |
120a6e |
TImageP img = m_lr->getFrameReader(m_fids[m_currIdx])->load();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (img) m_lw->getFrameWriter(m_fids[m_currIdx])->save(img);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void LevelUpdater::update(const TFrameId &fid, const TImageP &img) {
|
|
Shinya Kitaoka |
120a6e |
// Resume open for write
|
|
Shinya Kitaoka |
120a6e |
resume();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!m_usingTemporaryFile) {
|
|
Shinya Kitaoka |
120a6e |
// Plain random access write if supported
|
|
Shinya Kitaoka |
120a6e |
m_lw->getFrameWriter(fid)->save(img);
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Otherwise, we must add every frame preceding fid, and *then* add img.
|
|
Shinya Kitaoka |
120a6e |
// NOTE: This requires that the image sequence is already sorted by fid.
|
|
Shinya Kitaoka |
120a6e |
addFramesTo(std::lower_bound(m_fids.begin() + m_currIdx, m_fids.end(), fid) -
|
|
Shinya Kitaoka |
120a6e |
m_fids.begin());
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Save the passed image. In case it overwrites a frame, erase that from the
|
|
Shinya Kitaoka |
120a6e |
// list too.
|
|
Shinya Kitaoka |
120a6e |
m_lw->getFrameWriter(fid)->save(img);
|
|
Shinya Kitaoka |
120a6e |
if (m_currIdx < int(m_fids.size()) && m_fids[m_currIdx] == fid) ++m_currIdx;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void LevelUpdater::close() {
|
|
Shinya Kitaoka |
120a6e |
if (!m_opened) return;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Resume open for write
|
|
Shinya Kitaoka |
120a6e |
resume();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
try {
|
|
Shinya Kitaoka |
120a6e |
if (m_usingTemporaryFile) {
|
|
Shinya Kitaoka |
120a6e |
// Add all remaining frames still in m_fids
|
|
Shinya Kitaoka |
120a6e |
addFramesTo((int)m_fids.size());
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Currently written level is temporary. It must be renamed to its
|
|
Shinya Kitaoka |
120a6e |
// originally intended path,
|
|
Shinya Kitaoka |
120a6e |
// if it's possible to write there. Now, if it's writable, in particular
|
|
Shinya Kitaoka |
120a6e |
// it should be readable,
|
|
Shinya Kitaoka |
120a6e |
// so m_lr should exist.
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// If not... well, the file was corrupt or something. Instead than
|
|
Shinya Kitaoka |
120a6e |
// attempting to delete it,
|
|
Shinya Kitaoka |
120a6e |
// we're begin conservative - this means that no data is lost, but
|
|
Shinya Kitaoka |
120a6e |
// unfortunately temporaries
|
|
Shinya Kitaoka |
120a6e |
// might pile up...
|
|
Shinya Kitaoka |
120a6e |
if (m_lr) {
|
|
Shinya Kitaoka |
120a6e |
TFilePath finalPath(m_lr->getFilePath()), tempPath(m_lw->getFilePath());
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Release m_lr and m_lw - to be sure that no file is kept open while
|
|
Shinya Kitaoka |
120a6e |
// renaming.
|
|
Shinya Kitaoka |
120a6e |
// NOTE: releasing m_lr and m_lw should not throw anything. As stated
|
|
Shinya Kitaoka |
120a6e |
// before, throwing
|
|
Shinya Kitaoka |
120a6e |
// in destructors is bad. I'm not sure this is actually guaranteed
|
|
Shinya Kitaoka |
120a6e |
// in Toonz, however :(
|
|
Shinya Kitaoka |
120a6e |
m_lr = TLevelReaderP(), m_lw = TLevelWriterP();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Rename the level
|
|
Shinya Kitaoka |
120a6e |
TSystem::removeFileOrLevel_throw(finalPath);
|
|
Shinya Kitaoka |
120a6e |
TSystem::renameFileOrLevel_throw(finalPath,
|
|
Shinya Kitaoka |
120a6e |
tempPath); // finalPath <- tempPath
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// If present, add known trailing files
|
|
Shinya Kitaoka |
120a6e |
if (finalPath.getType() == "tlv") {
|
|
Shinya Kitaoka |
120a6e |
// Palette file
|
|
Shinya Kitaoka |
120a6e |
TFilePath finalPalette = finalPath.withType("tpl");
|
|
Shinya Kitaoka |
120a6e |
TFilePath tempPalette = tempPath.withType("tpl");
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (TFileStatus(finalPalette).doesExist()) {
|
|
Shinya Kitaoka |
120a6e |
if (TFileStatus(tempPalette).doesExist())
|
|
Shinya Kitaoka |
120a6e |
TSystem::deleteFile(finalPalette);
|
|
Shinya Kitaoka |
120a6e |
TSystem::renameFile(finalPalette, tempPalette);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// History file
|
|
Shinya Kitaoka |
120a6e |
TFilePath finalHistory = finalPath.withType("hst");
|
|
Shinya Kitaoka |
120a6e |
TFilePath tempHistory = tempPath.withType("hst");
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (TFileStatus(tempHistory).doesExist()) {
|
|
Shinya Kitaoka |
120a6e |
if (TFileStatus(finalHistory).doesExist())
|
|
Shinya Kitaoka |
120a6e |
TSystem::deleteFile(finalHistory);
|
|
Shinya Kitaoka |
120a6e |
TSystem::renameFile(finalHistory, tempHistory);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// NOTE: If for some reason m_lr was not present and we were using a
|
|
Shinya Kitaoka |
120a6e |
// temporary file, no
|
|
Shinya Kitaoka |
120a6e |
// renaming takes place. Users could see the __x temporaries and,
|
|
Shinya Kitaoka |
120a6e |
// eventually, rename them manually
|
|
Shinya Kitaoka |
120a6e |
// or see what's wrong with the unwritable file.
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Reset the updater's status
|
|
Shinya Kitaoka |
120a6e |
reset();
|
|
Shinya Kitaoka |
120a6e |
} catch (...) {
|
|
Shinya Kitaoka |
120a6e |
// Some temporary object could not be renamed. Or some remaining frame could
|
|
Shinya Kitaoka |
120a6e |
// not be added.
|
|
Shinya Kitaoka |
120a6e |
// Hopefully, it was not about closing m_lr or m_lw.
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// However, we still intend to reset the updater's status before rethrowing.
|
|
Shinya Kitaoka |
120a6e |
reset();
|
|
Shinya Kitaoka |
120a6e |
throw;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void LevelUpdater::flush() {
|
|
Shinya Kitaoka |
120a6e |
assert(m_opened);
|
|
Shinya Kitaoka |
120a6e |
if (!m_lw) return;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// In case the level writer could not be destroyed (bad, should really not
|
|
Shinya Kitaoka |
120a6e |
// throw btw),
|
|
Shinya Kitaoka |
120a6e |
// reset and rethrow
|
|
Shinya Kitaoka |
120a6e |
try {
|
|
Shinya Kitaoka |
120a6e |
m_lw = TLevelWriterP();
|
|
Shinya Kitaoka |
120a6e |
} catch (...) {
|
|
Shinya Kitaoka |
120a6e |
reset();
|
|
Shinya Kitaoka |
120a6e |
throw;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void LevelUpdater::resume() {
|
|
Shinya Kitaoka |
120a6e |
assert(m_opened);
|
|
Shinya Kitaoka |
120a6e |
if (m_lw) return;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
try {
|
|
Shinya Kitaoka |
120a6e |
m_lw = TLevelWriterP(m_lwPath, m_pg->clone());
|
|
Shinya Kitaoka |
120a6e |
} catch (...) {
|
|
Shinya Kitaoka |
120a6e |
reset();
|
|
Shinya Kitaoka |
120a6e |
throw;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|