tahoma2d/toonz/sources/toonz/keyframedata.cpp

221 lines
8.3 KiB
C++

#include "keyframedata.h"
#include "tapp.h"
#include "toonzqt/tselectionhandle.h"
#include "keyframeselection.h"
#include "xsheetviewer.h"
#include "toonz/txsheet.h"
#include "toonz/tstageobjecttree.h"
#include "toonz/tstageobjectkeyframe.h"
#include "toonz/txshcolumn.h"
#include "toonz/preferences.h"
#include <assert.h>
//=============================================================================
// TKeyframeData
//-----------------------------------------------------------------------------
TKeyframeData::TKeyframeData() {}
//-----------------------------------------------------------------------------
TKeyframeData::TKeyframeData(const TKeyframeData *src)
: m_keyData(src->m_keyData)
, m_isPegbarsCycleEnabled(src->m_isPegbarsCycleEnabled)
, m_offset(src->m_offset) {}
//-----------------------------------------------------------------------------
TKeyframeData::~TKeyframeData() {}
//-----------------------------------------------------------------------------
// data <- xsheet
void TKeyframeData::setKeyframes(std::set<Position> positions, TXsheet *xsh) {
Position startPos(-1, -1);
setKeyframes(positions, xsh, startPos);
}
void TKeyframeData::setKeyframes(std::set<Position> positions, TXsheet *xsh,
Position startPos) {
if (positions.empty()) return;
TStageObjectId cameraId =
TStageObjectId::CameraId(xsh->getCameraColumnIndex());
std::set<Position>::iterator it = positions.begin();
int r0 = it->first;
int c0 = it->second;
int r1 = it->first;
int c1 = it->second;
for (++it; it != positions.end(); ++it) {
r0 = std::min(r0, it->first);
c0 = std::min(c0, it->second);
r1 = std::max(r1, it->first);
c1 = std::max(c1, it->second);
}
m_columnSpanCount = c1 - c0 + 1;
m_rowSpanCount = r1 - r0 + 1;
if (startPos.first >= 0 && startPos.second >= 0)
m_offset = std::make_pair(r0 - startPos.first, c0 - startPos.second);
for (it = positions.begin(); it != positions.end(); ++it) {
int row = it->first;
int col = it->second;
TStageObject *pegbar = xsh->getStageObject(
col >= 0 ? TStageObjectId::ColumnId(col) : cameraId);
assert(pegbar);
m_isPegbarsCycleEnabled[col] = pegbar->isCycleEnabled();
if (pegbar->isKeyframe(row)) {
Position p(row - r0, col - c0);
TStageObject::Keyframe k = pegbar->getKeyframe(row);
m_keyData[p] = k;
}
}
}
//-----------------------------------------------------------------------------
// data -> xsh
bool TKeyframeData::getKeyframes(std::set<Position> &positions,
TXsheet *xsh) const {
std::set<TKeyframeSelection::Position>::iterator it2 = positions.begin();
int r0 = it2->first;
int c0 = it2->second;
std::map<int, int> firstRowCol, lastRowCol;
firstRowCol.insert(std::pair<int, int>(c0, r0));
lastRowCol.insert(std::pair<int, int>(c0, r0));
for (++it2; it2 != positions.end(); ++it2) {
r0 = std::min(r0, it2->first);
c0 = std::min(c0, it2->second);
std::map<int, int>::iterator itF = firstRowCol.find(it2->second);
std::map<int, int>::iterator itL = lastRowCol.find(it2->second);
if (itF == firstRowCol.end())
firstRowCol.insert(std::pair<int, int>(it2->second, it2->first));
if (itL == lastRowCol.end())
lastRowCol.insert(std::pair<int, int>(it2->second, it2->first));
else
itL->second = c0;
}
XsheetViewer *viewer = TApp::instance()->getCurrentXsheetViewer();
positions.clear();
TStageObjectId cameraId =
TStageObjectId::CameraId(xsh->getCameraColumnIndex());
Iterator it;
bool keyFrameChanged = false;
for (it = m_keyData.begin(); it != m_keyData.end(); ++it) {
Position pos = it->first;
int row = r0 + pos.first;
int col = c0 + pos.second;
positions.insert(std::make_pair(row, col));
TXshColumn *column = xsh->getColumn(col);
if (column && column->getSoundColumn()) continue;
TStageObject *pegbar = xsh->getStageObject(
col >= 0 ? TStageObjectId::ColumnId(col) : cameraId);
if (xsh->getColumn(col) && xsh->getColumn(col)->isLocked()) continue;
keyFrameChanged = true;
assert(pegbar);
int kF, kL, kP, kN;
double e0, e1;
pegbar->getKeyframeRange(kF, kL);
pegbar->setKeyframeWithoutUndo(row, it->second);
std::map<int, int>::iterator itF = firstRowCol.find(col);
std::map<int, int>::iterator itL = lastRowCol.find(col);
TStageObject::Keyframe newKey = pegbar->getKeyframe(row);
// Process 1st key added in column
if (itF != firstRowCol.end() && itF->second == row) {
if (row > kL) {
// If new key was added after the existing last one, create new
// interpolation between them using preference setting
TStageObject::Keyframe prevKey = pegbar->getKeyframe(kL);
for (int i = 0; i < TStageObject::T_ChannelCount; i++) {
if (newKey.m_channels[i].m_isKeyframe &&
prevKey.m_channels[i].m_isKeyframe) {
prevKey.m_channels[i].m_type = TDoubleKeyframe::Type(
Preferences::instance()->getKeyframeType());
newKey.m_channels[i].m_prevType = prevKey.m_channels[i].m_type;
}
}
pegbar->setKeyframeWithoutUndo(kL, prevKey);
pegbar->setKeyframeWithoutUndo(row, newKey);
} else if (row > kF) {
// If new key was added between existing keys, sync new key's previous
// interpolation to key just before it
if (!pegbar->getKeyframeSpan(row - 1, kP, e0, kN, e1)) kP = row - 1;
TStageObject::Keyframe prevKey = pegbar->getKeyframe(kP);
for (int i = 0; i < TStageObject::T_ChannelCount; i++) {
if (newKey.m_channels[i].m_isKeyframe &&
prevKey.m_channels[i].m_isKeyframe)
newKey.m_channels[i].m_prevType = prevKey.m_channels[i].m_type;
}
pegbar->setKeyframeWithoutUndo(row, newKey);
}
}
// Process last key added in column
if (itL != lastRowCol.end() && itL->second == row) {
if (row < kF) {
// If new key was added before the existing 1st one, create new
// interpolation between them using preference setting
TStageObject::Keyframe nextKey = pegbar->getKeyframe(kF);
for (int i = 0; i < TStageObject::T_ChannelCount; i++) {
if (newKey.m_channels[i].m_isKeyframe &&
nextKey.m_channels[i].m_isKeyframe) {
newKey.m_channels[i].m_type = TDoubleKeyframe::Type(
Preferences::instance()->getKeyframeType());
nextKey.m_channels[i].m_prevType = newKey.m_channels[i].m_type;
}
}
pegbar->setKeyframeWithoutUndo(row, newKey);
pegbar->setKeyframeWithoutUndo(kF, nextKey);
} else if (row < kL) {
// If new key was added between existing keys, sync new key to the next
// key's previous interpolation
if (!pegbar->getKeyframeSpan(row + 1, kP, e0, kN, e1)) kN = row + 1;
TStageObject::Keyframe nextKey = pegbar->getKeyframe(kN);
for (int i = 0; i < TStageObject::T_ChannelCount; i++) {
if (newKey.m_channels[i].m_isKeyframe &&
nextKey.m_channels[i].m_isKeyframe) {
nextKey.m_channels[i].m_prevType = newKey.m_channels[i].m_type;
}
}
pegbar->setKeyframeWithoutUndo(row, newKey);
}
}
}
if (!keyFrameChanged) return false;
for (auto const pegbar : m_isPegbarsCycleEnabled) {
int const col = pegbar.first;
TStageObjectId objectId =
(col >= 0) ? TStageObjectId::ColumnId(col) : cameraId;
xsh->getStageObject(objectId)->enableCycle(pegbar.second);
}
return true;
}
//-----------------------------------------------------------------------------
void TKeyframeData::getKeyframes(std::set<Position> &positions) const {
int r0 = positions.begin()->first;
int c0 = positions.begin()->second;
positions.clear();
TKeyframeData::KeyData::const_iterator it;
for (it = m_keyData.begin(); it != m_keyData.end(); ++it) {
TKeyframeData::Position pos(it->first);
positions.insert(
TKeyframeSelection::Position(pos.first + r0, pos.second + c0));
}
}
void TKeyframeData::setKeyframesOffset(int row, int col) {
m_offset = std::make_pair(row, col);
}