Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzBase includes
Toshihiro Shimizu 890ddd
#include "tfxattributes.h"
Toshihiro Shimizu 890ddd
#include "tfxutil.h"
Toshihiro Shimizu 890ddd
#include "tmacrofx.h"
Toshihiro Shimizu 890ddd
#include "toutputproperties.h"
Toshihiro Shimizu 890ddd
#include "tparamcontainer.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/txsheet.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobjecttree.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcolumnfx.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcolumnfxset.h"
Toshihiro Shimizu 890ddd
#include "toonz/fxdag.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshchildlevel.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshcell.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshleveltypes.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshlevelcolumn.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshpalettecolumn.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshzeraryfxcolumn.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshsimplelevel.h"
Toshihiro Shimizu 890ddd
#include "toonz/dpiscale.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcamera.h"
Toshihiro Shimizu 890ddd
#include "toonz/toonzscene.h"
Toshihiro Shimizu 890ddd
#include "toonz/sceneproperties.h"
Toshihiro Shimizu 890ddd
#include "toonz/plasticdeformerfx.h"
Toshihiro Shimizu 890ddd
#include "toonz/stage.h"
Toshihiro Shimizu 890ddd
#include "toonz/preferences.h"
Toshihiro Shimizu 890ddd
#include "ttzpimagefx.h"
shun-iwasawa 5b2332
#include "toonz/txshsoundtextcolumn.h"
shun-iwasawa 5b2332
#include "toonz/txshsoundtextlevel.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "../stdfx/motionawarebasefx.h"
shun-iwasawa 5b2332
#include "../stdfx/textawarebasefx.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/scenefx.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Shinya Kitaoka 120a6e
  TODO: Some parts of the following render-tree building procedure should be
Shinya Kitaoka 120a6e
  revised. In particular,
Shinya Kitaoka 120a6e
        there is scarce support for frame-shifting fxs, whenever the frame-shift
Shinya Kitaoka 120a6e
  can be resolved
Toshihiro Shimizu 890ddd
        only during rendering (as is the case for ParticlesFx).
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
//    TimeShuffleFx  definition
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! TimeShuffleFx is the rendering-tree equivalent of a sub-xsheet column.
Toshihiro Shimizu 890ddd
/*!
Shinya Kitaoka 120a6e
  TimeShuffleFx is a special-purpose fx which is used in render-tree building
Shinya Kitaoka 120a6e
procedures
Toshihiro Shimizu 890ddd
  to simulate the effect of a sub-xsheet.
Toshihiro Shimizu 890ddd
\n\n
Shinya Kitaoka 120a6e
  A rendering tree is a fully expanded tree that mixes implicit xsheet nesting
Shinya Kitaoka 120a6e
with
Shinya Kitaoka 120a6e
  the explicit fxs dag  for a specific frame <\I>. Since the frame the tree
Shinya Kitaoka 120a6e
is developed from
Toshihiro Shimizu 890ddd
  is fixed, a sub-xsheet can be seen as a  frame setter <\I> fx.
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class TimeShuffleFx final : public TRasterFx {
Shinya Kitaoka 120a6e
  FX_DECLARATION(TimeShuffleFx)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  int m_frame;                 //!< Frame this fx redirects to
Shinya Kitaoka 120a6e
  TFxTimeRegion m_timeRegion;  //!< Input (outer) valid column frame range
Shinya Kitaoka 120a6e
  TRasterFxPort m_port;        //!< Input port
shun-iwasawa 0b8813
  TXshCellColumn *m_cellColumn;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
shun-iwasawa 0b8813
  TimeShuffleFx()
shun-iwasawa 0b8813
      : TRasterFx(), m_frame(0), m_timeRegion(), m_cellColumn(nullptr) {
Shinya Kitaoka 120a6e
    addInputPort("source", m_port);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  ~TimeShuffleFx() {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  TFx *clone(bool recursive = true) const override {
Shinya Kitaoka 120a6e
    TimeShuffleFx *fx = dynamic_cast<timeshufflefx *="">(TFx::clone(recursive));</timeshufflefx>
Shinya Kitaoka 120a6e
    assert(fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    fx->setFrame(m_frame);
Shinya Kitaoka 120a6e
    fx->setTimeRegion(getTimeRegion());
shun-iwasawa 0b8813
    fx->setCellColumn(m_cellColumn);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    return fx;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int getFrame() const { return m_frame; }
Shinya Kitaoka 120a6e
  void setFrame(int frame) { m_frame = frame; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void setTimeRegion(const TFxTimeRegion &timeRegion) {
Shinya Kitaoka 120a6e
    m_timeRegion = timeRegion;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  TFxTimeRegion getTimeRegion() const override { return m_timeRegion; }
Toshihiro Shimizu 890ddd
shun-iwasawa 0b8813
  void setCellColumn(TXshCellColumn *cellColumn) { m_cellColumn = cellColumn; }
shun-iwasawa 0b8813
Shinya Kitaoka 38fd86
  bool canHandle(const TRenderSettings &info, double frame) override {
Shinya Kitaoka 38fd86
    return true;
Shinya Kitaoka 38fd86
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  std::string getPluginId() const override { return std::string(); }
Toshihiro Shimizu 890ddd
shun-iwasawa 0b8813
  int getLevelFrame(int frame) const {
shun-iwasawa 0b8813
    if (!m_cellColumn) return m_frame;
shun-iwasawa 0b8813
    TXshCell cell = m_cellColumn->getCell(tfloor(frame));
shun-iwasawa 0b8813
    assert(!cell.isEmpty());
shun-iwasawa 0b8813
    return cell.m_frameId.getNumber() - 1;
shun-iwasawa 0b8813
  }
shun-iwasawa 0b8813
Shinya Kitaoka 38fd86
  void doCompute(TTile &tile, double frame,
Shinya Kitaoka 38fd86
                 const TRenderSettings &ri) override {
Shinya Kitaoka 120a6e
    if (!m_port.isConnected()) {
Shinya Kitaoka 120a6e
      tile.getRaster()->clear();
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Exchange frame with the stored one
shun-iwasawa 0b8813
    TRasterFxP(m_port.getFx())->compute(tile, getLevelFrame(frame), ri);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 38fd86
  bool doGetBBox(double frame, TRectD &bbox,
Shinya Kitaoka 38fd86
                 const TRenderSettings &info) override {
Shinya Kitaoka 120a6e
    if (!m_port.isConnected()) return false;
shun-iwasawa 0b8813
    return TRasterFxP(m_port.getFx())
shun-iwasawa 0b8813
        ->doGetBBox(getLevelFrame(frame), bbox, info);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 38fd86
  std::string getAlias(double frame,
Shinya Kitaoka 38fd86
                       const TRenderSettings &info) const override {
shun-iwasawa 0b8813
    return TRasterFx::getAlias(getLevelFrame(frame), info);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 38fd86
  void doDryCompute(TRectD &rect, double frame,
Shinya Kitaoka 38fd86
                    const TRenderSettings &info) override {
Shinya Kitaoka 120a6e
    if (m_port.isConnected())
shun-iwasawa 0b8813
      TRasterFxP(m_port.getFx())->dryCompute(rect, getLevelFrame(frame), info);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  // not implemented
Shinya Kitaoka 120a6e
  TimeShuffleFx(const TimeShuffleFx &);
Shinya Kitaoka 120a6e
  TimeShuffleFx &operator=(const TimeShuffleFx &);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
FX_IDENTIFIER_IS_HIDDEN(TimeShuffleFx, "timeShuffleFx")
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
//    AffineFx  definition
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! AffineFx is a specialization of TGeometryFx which implements animated or
Shinya Kitaoka 120a6e
//! stage-controlled affines
Toshihiro Shimizu 890ddd
/*!
Shinya Kitaoka 120a6e
  This specific implementation of TGeometryFx is needed to deal with those
Shinya Kitaoka 120a6e
  affines which are best
Toshihiro Shimizu 890ddd
  \b not resolved during the rendering-tree expansion procedure.
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class AffineFx final : public TGeometryFx {
Shinya Kitaoka 120a6e
  FX_DECLARATION(AffineFx)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  TXsheet *m_xsheet;            //!< Xsheet owning m_stageObject
Shinya Kitaoka 120a6e
  TStageObject *m_stageObject;  //!< The stage object this AffineFx refers to
Shinya Kitaoka 120a6e
  TRasterFxPort m_input;        //!< The input port
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  AffineFx() : m_xsheet(0), m_stageObject(0) {
Shinya Kitaoka 120a6e
    addInputPort("source", m_input);
Shinya Kitaoka 120a6e
    setName(L"AffineFx");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  AffineFx(TXsheet *xsh, TStageObject *pegbar)
Shinya Kitaoka 120a6e
      : m_xsheet(xsh), m_stageObject(pegbar) {
Shinya Kitaoka 120a6e
    addInputPort("source", m_input);
Shinya Kitaoka 120a6e
    setName(L"AffineFx");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  ~AffineFx() {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  TFx *clone(bool recursive = true) const override {
Shinya Kitaoka 120a6e
    AffineFx *fx = dynamic_cast<affinefx *="">(TFx::clone(recursive));</affinefx>
Shinya Kitaoka 120a6e
    assert(fx);
Shinya Kitaoka 120a6e
    fx->m_stageObject = m_stageObject;
Shinya Kitaoka 120a6e
    fx->m_xsheet      = m_xsheet;
Shinya Kitaoka 120a6e
    return fx;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 38fd86
  bool canHandle(const TRenderSettings &info, double frame) override {
Shinya Kitaoka 38fd86
    return true;
Shinya Kitaoka 38fd86
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  TAffine getPlacement(double frame) override {
Shinya Kitaoka 120a6e
    TAffine objAff = m_stageObject->getPlacement(frame);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double objZ        = m_stageObject->getZ(frame);
Shinya Kitaoka 120a6e
    double objNoScaleZ = m_stageObject->getGlobalNoScaleZ();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TStageObjectId cameraId =
Shinya Kitaoka 120a6e
        m_xsheet->getStageObjectTree()->getCurrentCameraId();
Shinya Kitaoka 120a6e
    TStageObject *camera = m_xsheet->getStageObject(cameraId);
Shinya Kitaoka 120a6e
    TAffine cameraAff    = camera->getPlacement(frame);
Shinya Kitaoka 120a6e
    double cameraZ       = camera->getZ(frame);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TAffine aff;
Shinya Kitaoka 120a6e
    bool isVisible = TStageObject::perspective(aff, cameraAff, cameraZ, objAff,
Shinya Kitaoka 120a6e
                                               objZ, objNoScaleZ);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!isVisible)
Shinya Kitaoka 120a6e
      return TAffine();  // uh oh
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return aff;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  TAffine getParentPlacement(double frame) override {
Shinya Kitaoka 120a6e
    return m_stageObject->getPlacement(frame);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  std::string getPluginId() const override { return std::string(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  // not implemented
Shinya Kitaoka 120a6e
  AffineFx(const AffineFx &);
Shinya Kitaoka 120a6e
  AffineFx &operator=(const AffineFx &);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
FX_IDENTIFIER_IS_HIDDEN(AffineFx, "affineFx")
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
//    PlacedFx  definition
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! PlacedFx is the enriched form of a TRasterFx during render-tree building.
Shinya Kitaoka 120a6e
class PlacedFx {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  double m_z;         //!< Z value for this fx's column
Shinya Kitaoka 120a6e
  double m_so;        //!< Same as above, for stacking order
Shinya Kitaoka 120a6e
  int m_columnIndex;  //!< This fx's column index
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFxP m_fx;      //!< The referenced fx
Shinya Kitaoka 120a6e
  TAffine m_aff;  //!<
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFxPort *m_leftXsheetPort;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  PlacedFx()
Shinya Kitaoka 120a6e
      : m_z(0)
Shinya Kitaoka 120a6e
      , m_so(0)
Shinya Kitaoka 120a6e
      , m_columnIndex(-1)
Shinya Kitaoka 120a6e
      , m_fx(0)
Shinya Kitaoka 120a6e
      , m_aff()
Shinya Kitaoka 120a6e
      , m_leftXsheetPort(0) {}
Shinya Kitaoka 120a6e
  explicit PlacedFx(const TFxP &fx)
Shinya Kitaoka 120a6e
      : m_z(0)
Shinya Kitaoka 120a6e
      , m_so(0)
Shinya Kitaoka 120a6e
      , m_columnIndex(-1)
Shinya Kitaoka 120a6e
      , m_fx(fx)
Shinya Kitaoka 120a6e
      , m_aff()
Shinya Kitaoka 120a6e
      , m_leftXsheetPort(0) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool operator<(const PlacedFx &pf) const {
Shinya Kitaoka 120a6e
    return (m_z < pf.m_z)
Shinya Kitaoka 120a6e
               ? true
Shinya Kitaoka 120a6e
               : (m_z > pf.m_z)
Shinya Kitaoka 120a6e
                     ? false
Shinya Kitaoka 120a6e
                     : (m_so < pf.m_so)
Shinya Kitaoka 120a6e
                           ? true
Shinya Kitaoka 120a6e
                           : (m_so > pf.m_so)
Shinya Kitaoka 120a6e
                                 ? false
Shinya Kitaoka 120a6e
                                 : (m_columnIndex < pf.m_columnIndex);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFxP makeFx() {
shun-iwasawa 0b8813
    return (!m_fx)
shun-iwasawa 0b8813
               ? TFxP()
shun-iwasawa 0b8813
               : (m_aff == TAffine()) ? m_fx : TFxUtil::makeAffine(m_fx, m_aff);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
shun-iwasawa 0b8813
TFxP timeShuffle(TFxP fx, int frame, TFxTimeRegion timeRegion,
shun-iwasawa 0b8813
                 TXshCellColumn *cellColumn) {
Shinya Kitaoka 120a6e
  TimeShuffleFx *timeShuffle = new TimeShuffleFx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  timeShuffle->setFrame(frame);
Shinya Kitaoka 120a6e
  timeShuffle->setTimeRegion(timeRegion);
shun-iwasawa 0b8813
  timeShuffle->setCellColumn(cellColumn);
Shinya Kitaoka 120a6e
  if (!timeShuffle->connect("source", fx.getPointer()))
Shinya Kitaoka 120a6e
    assert(!"Could not connect ports!");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return timeShuffle;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
//    Column-related functions
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool getColumnPlacement(TAffine &aff, TXsheet *xsh, double row, int col,
Shinya Kitaoka 120a6e
                        bool isPreview) {
Shinya Kitaoka 120a6e
  if (col < 0) return false;
Shinya Kitaoka 120a6e
  TStageObject *pegbar = xsh->getStageObject(TStageObjectId::ColumnId(col));
Shinya Kitaoka 120a6e
  TAffine objAff       = pegbar->getPlacement(row);
Shinya Kitaoka 120a6e
  double objZ          = pegbar->getZ(row);
Shinya Kitaoka 120a6e
  double noScaleZ      = pegbar->getGlobalNoScaleZ();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TStageObjectId cameraId;
Shinya Kitaoka 120a6e
  if (isPreview)
Shinya Kitaoka 120a6e
    cameraId = xsh->getStageObjectTree()->getCurrentPreviewCameraId();
Shinya Kitaoka 120a6e
  else
shun-iwasawa 0b8813
    cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
Shinya Kitaoka 120a6e
  TStageObject *camera = xsh->getStageObject(cameraId);
Shinya Kitaoka 120a6e
  TAffine cameraAff    = camera->getPlacement(row);
Shinya Kitaoka 120a6e
  double cameraZ       = camera->getZ(row);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool isVisible = TStageObject::perspective(aff, cameraAff, cameraZ, objAff,
Shinya Kitaoka 120a6e
                                             objZ, noScaleZ);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return isVisible;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Campbell Barton b3bd84
static bool getColumnPlacement(PlacedFx &pf, TXsheet *xsh, double row, int col,
Campbell Barton b3bd84
                               bool isPreview) {
Shinya Kitaoka 120a6e
  if (col < 0) return false;
Shinya Kitaoka 120a6e
  TStageObject *pegbar = xsh->getStageObject(TStageObjectId::ColumnId(col));
Shinya Kitaoka 120a6e
  TAffine objAff       = pegbar->getPlacement(row);
Shinya Kitaoka 120a6e
  pf.m_z               = pegbar->getZ(row);
Shinya Kitaoka 120a6e
  pf.m_so              = pegbar->getSO(row);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TStageObjectId cameraId;
Shinya Kitaoka 120a6e
  if (isPreview)
Shinya Kitaoka 120a6e
    cameraId = xsh->getStageObjectTree()->getCurrentPreviewCameraId();
Shinya Kitaoka 120a6e
  else
shun-iwasawa 0b8813
    cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
Shinya Kitaoka 120a6e
  TStageObject *camera = xsh->getStageObject(cameraId);
Shinya Kitaoka 120a6e
  TAffine cameraAff    = camera->getPlacement(row);
Shinya Kitaoka 120a6e
  double cameraZ       = camera->getZ(row);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool isVisible =
Shinya Kitaoka 120a6e
      TStageObject::perspective(pf.m_aff, cameraAff, cameraZ, objAff, pf.m_z,
Shinya Kitaoka 120a6e
                                pegbar->getGlobalNoScaleZ());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return isVisible;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*-- Objectの位置を得る --*/
Campbell Barton b3bd84
static bool getStageObjectPlacement(TAffine &aff, TXsheet *xsh, double row,
Campbell Barton b3bd84
                                    TStageObjectId &id, bool isPreview) {
Shinya Kitaoka 120a6e
  TStageObject *pegbar = xsh->getStageObjectTree()->getStageObject(id, false);
Shinya Kitaoka 120a6e
  if (!pegbar) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TAffine objAff  = pegbar->getPlacement(row);
Shinya Kitaoka 120a6e
  double objZ     = pegbar->getZ(row);
Shinya Kitaoka 120a6e
  double noScaleZ = pegbar->getGlobalNoScaleZ();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TStageObjectId cameraId;
Shinya Kitaoka 120a6e
  if (isPreview)
Shinya Kitaoka 120a6e
    cameraId = xsh->getStageObjectTree()->getCurrentPreviewCameraId();
Shinya Kitaoka 120a6e
  else
shun-iwasawa 0b8813
    cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
Shinya Kitaoka 120a6e
  TStageObject *camera = xsh->getStageObject(cameraId);
Shinya Kitaoka 120a6e
  TAffine cameraAff    = camera->getPlacement(row);
Shinya Kitaoka 120a6e
  double cameraZ       = camera->getZ(row);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool isVisible = TStageObject::perspective(aff, cameraAff, cameraZ, objAff,
Shinya Kitaoka 120a6e
                                             objZ, noScaleZ);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return isVisible;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*-- typeとindexからStageObjectIdを得る --*/
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
TStageObjectId getMotionObjectId(MotionObjectType type, int index) {
Shinya Kitaoka 120a6e
  switch (type) {
Shinya Kitaoka 120a6e
  case OBJTYPE_OWN:
Shinya Kitaoka 120a6e
    return TStageObjectId::NoneId;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case OBJTYPE_COLUMN:
Shinya Kitaoka 120a6e
    if (index == 0) return TStageObjectId::NoneId;
Shinya Kitaoka 120a6e
    return TStageObjectId::ColumnId(index - 1);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case OBJTYPE_PEGBAR:
Shinya Kitaoka 120a6e
    if (index == 0) return TStageObjectId::NoneId;
Shinya Kitaoka 120a6e
    return TStageObjectId::PegbarId(index - 1);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case OBJTYPE_TABLE:
Shinya Kitaoka 120a6e
    return TStageObjectId::TableId;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case OBJTYPE_CAMERA:
Shinya Kitaoka 120a6e
    if (index == 0) return TStageObjectId::NoneId;
Shinya Kitaoka 120a6e
    return TStageObjectId::CameraId(index - 1);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return TStageObjectId::NoneId;
Toshihiro Shimizu 890ddd
}
Shinya Kitaoka 120a6e
};  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun-iwasawa 27b0cf
static TPointD getColumnSpeed(TXsheet *xsh, double row, int col,
shun-iwasawa 27b0cf
                              bool isPreview) {
Shinya Kitaoka 120a6e
  TAffine aff;
Shinya Kitaoka 120a6e
  TPointD a, b;
Shinya Kitaoka 120a6e
  const double h = 0.001;
Shinya Kitaoka 120a6e
  getColumnPlacement(aff, xsh, row + h, col, isPreview);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*-- カラムと、カメラの動きに反応 --*/
Shinya Kitaoka 120a6e
  TStageObjectId cameraId;
Shinya Kitaoka 120a6e
  if (isPreview)
Shinya Kitaoka 120a6e
    cameraId = xsh->getStageObjectTree()->getCurrentPreviewCameraId();
Shinya Kitaoka 120a6e
  else
shun-iwasawa 0b8813
    cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
Shinya Kitaoka 120a6e
  TStageObject *camera = xsh->getStageObject(cameraId);
Shinya Kitaoka 120a6e
  TAffine cameraAff    = camera->getPlacement(row + h);
Shinya Kitaoka 120a6e
  a                    = aff * TPointD(-cameraAff.a13, -cameraAff.a23);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  aff = TAffine();
Shinya Kitaoka 120a6e
  getColumnPlacement(aff, xsh, row - h, col, isPreview);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  cameraAff = camera->getPlacement(row - h);
Shinya Kitaoka 120a6e
  b         = aff * TPointD(-cameraAff.a13, -cameraAff.a23);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return (b - a) * (0.5 / h);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*-- オブジェクトの軌跡を、基準点との差分で得る
Shinya Kitaoka 120a6e
        objectId: 移動の参考にするオブジェクト。自分自身の場合はNoneId
Toshihiro Shimizu 890ddd
--*/
Campbell Barton b3bd84
static QList<tpointd> getColumnMotionPoints(TXsheet *xsh, double row, int col,</tpointd>
shun-iwasawa 27b0cf
                                            TStageObjectId &objectId,
shun-iwasawa 27b0cf
                                            bool isPreview, double shutterStart,
shun-iwasawa 27b0cf
                                            double shutterEnd,
Campbell Barton b3bd84
                                            int traceResolution) {
Shinya Kitaoka 120a6e
  /*-- 前後フレームが共に0なら空のリストを返す --*/
Shinya Kitaoka 120a6e
  if (shutterStart == 0.0 && shutterEnd == 0.0) return QList<tpointd>();</tpointd>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*-- 現在のカメラを得る --*/
Shinya Kitaoka 120a6e
  TStageObjectId cameraId;
Shinya Kitaoka 120a6e
  if (isPreview)
Shinya Kitaoka 120a6e
    cameraId = xsh->getStageObjectTree()->getCurrentPreviewCameraId();
Shinya Kitaoka 120a6e
  else
shun-iwasawa 0b8813
    cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
Shinya Kitaoka 120a6e
  TStageObject *camera = xsh->getStageObject(cameraId);
Shinya Kitaoka 120a6e
  TAffine dpiAff       = getDpiAffine(camera->getCamera());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*-- 基準点の位置を得る --*/
Shinya Kitaoka 120a6e
  TAffine aff;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*-- objectIdが有効なものかどうかチェック --*/
Shinya Kitaoka 120a6e
  bool useOwnMotion = false;
Shinya Kitaoka 120a6e
  if (objectId == TStageObjectId::NoneId ||
Shinya Kitaoka 120a6e
      !xsh->getStageObjectTree()->getStageObject(objectId, false)) {
Shinya Kitaoka 120a6e
    getColumnPlacement(aff, xsh, row, col, isPreview);
Shinya Kitaoka 120a6e
    useOwnMotion = true;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    getStageObjectPlacement(aff, xsh, row, objectId, isPreview);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TAffine cameraAff = camera->getPlacement(row);
Shinya Kitaoka 120a6e
  TPointD basePos =
Shinya Kitaoka 120a6e
      dpiAff.inv() * aff * TPointD(-cameraAff.a13, -cameraAff.a23);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*-- 結果を収めるリスト --*/
Shinya Kitaoka 120a6e
  QList<tpointd> points;</tpointd>
Shinya Kitaoka 120a6e
  /*-- 軌跡点間のフレーム間隔 --*/
Shinya Kitaoka 120a6e
  double dFrame = (shutterStart + shutterEnd) / (double)traceResolution;
Shinya Kitaoka 120a6e
  /*-- 各点の位置を、基準点との差分で格納していく --*/
Shinya Kitaoka 120a6e
  for (int i = 0; i <= traceResolution; i++) {
Shinya Kitaoka 120a6e
    /*-- 基準位置とのフレーム差 --*/
Shinya Kitaoka 120a6e
    double frameOffset = -shutterStart + dFrame * (double)i;
Shinya Kitaoka 120a6e
    /*-- 基準位置とのフレーム差が無ければ、基準点に一致するので差分は0を入れる
Shinya Kitaoka 120a6e
     * --*/
Shinya Kitaoka 120a6e
    if (frameOffset == 0.0) {
Shinya Kitaoka 120a6e
      points.append(TPointD(0.0, 0.0));
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
shun-iwasawa a048bc
    double targetFrame = row + frameOffset;
shun-iwasawa a048bc
    // Proper position cannot be obtained for frame = -1.0
shun-iwasawa a048bc
    if (targetFrame == -1.0) targetFrame = -0.9999;
shun-iwasawa a048bc
Shinya Kitaoka 120a6e
    /*-- 自分自身の動きを使うか、別オブジェクトの動きを使うか --*/
Shinya Kitaoka 120a6e
    if (useOwnMotion)
shun-iwasawa a048bc
      getColumnPlacement(aff, xsh, targetFrame, col, isPreview);
Shinya Kitaoka 120a6e
    else
shun-iwasawa a048bc
      getStageObjectPlacement(aff, xsh, targetFrame, objectId, isPreview);
Shinya Kitaoka 120a6e
shun-iwasawa a048bc
    TAffine cameraAff = camera->getPlacement(targetFrame);
Shinya Kitaoka 120a6e
    TPointD tmpPos =
Shinya Kitaoka 120a6e
        dpiAff.inv() * aff * TPointD(-cameraAff.a13, -cameraAff.a23);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    /*-- 基準位置との差を記録 --*/
Shinya Kitaoka 120a6e
    points.append(tmpPos - basePos);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return points;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
shun-iwasawa 5b2332
namespace {
shun-iwasawa 5b2332
shun-iwasawa 5b2332
QString getNoteText(TXsheet *xsh, double row, int col, int noteColumnIndex,
shun-iwasawa 5b2332
                    bool neighbor) {
shun-iwasawa 5b2332
  int colIndex;
shun-iwasawa 5b2332
  if (neighbor)
shun-iwasawa 5b2332
    colIndex = col - 1;
shun-iwasawa 5b2332
  else
shun-iwasawa 5b2332
    colIndex = noteColumnIndex;
shun-iwasawa 5b2332
shun-iwasawa 5b2332
  TXshColumn *column = xsh->getColumn(colIndex);
shun-iwasawa 5b2332
  if (!column || !column->getSoundTextColumn()) return QString();
shun-iwasawa 5b2332
shun-iwasawa 5b2332
  TXshCell cell = xsh->getCell(row, colIndex);
shun-iwasawa 5b2332
  if (cell.isEmpty() || !cell.getSoundTextLevel()) return QString();
shun-iwasawa 5b2332
shun-iwasawa 5b2332
  return cell.getSoundTextLevel()->getFrameText(cell.m_frameId.getNumber() - 1);
shun-iwasawa 5b2332
}
shun-iwasawa 0b8813
};  // namespace
shun-iwasawa 5b2332
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
//    FxBuilder  definition
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class FxBuilder {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  ToonzScene *m_scene;
Shinya Kitaoka 120a6e
  TXsheet *m_xsh;
Shinya Kitaoka 120a6e
  TAffine m_cameraAff;
Shinya Kitaoka 120a6e
  double m_cameraZ;
Shinya Kitaoka 120a6e
  double m_frame;
Shinya Kitaoka 120a6e
  int m_whichLevels;
Shinya Kitaoka 120a6e
  bool m_isPreview;
Shinya Kitaoka 120a6e
  bool m_expandXSheet;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // in the makePF() methods m_particleDescendentCount>0 iff the TFx* is an
Shinya Kitaoka 120a6e
  // ancestor
Shinya Kitaoka 120a6e
  // (at least) of a particle Fx
Shinya Kitaoka 120a6e
  int m_particleDescendentCount;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  FxBuilder(ToonzScene *scene, TXsheet *xsh, double frame, int whichLevels,
Shinya Kitaoka 120a6e
            bool isPreview = false, bool expandXSheet = true);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFxP buildFx();
Shinya Kitaoka 120a6e
  TFxP buildFx(const TFxP &root, BSFX_Transforms_Enum transforms);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  PlacedFx makePF(TLevelColumnFx *fx);
Shinya Kitaoka 120a6e
  PlacedFx makePF(TPaletteColumnFx *fx);
Shinya Kitaoka 120a6e
  PlacedFx makePF(TZeraryColumnFx *fx);
Shinya Kitaoka 120a6e
  PlacedFx makePF(TXsheetFx *fx);
Shinya Kitaoka 120a6e
  PlacedFx makePFfromUnaryFx(TFx *fx);
Shinya Kitaoka 120a6e
  PlacedFx makePFfromGenericFx(TFx *fx);
Shinya Kitaoka 120a6e
  PlacedFx makePF(TFx *fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFxP getFxWithColumnMovements(const PlacedFx &pf);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool addPlasticDeformerFx(PlacedFx &pf);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
FxBuilder::FxBuilder(ToonzScene *scene, TXsheet *xsh, double frame,
Shinya Kitaoka 120a6e
                     int whichLevels, bool isPreview, bool expandXSheet)
Shinya Kitaoka 120a6e
    : m_scene(scene)
Shinya Kitaoka 120a6e
    , m_xsh(xsh)
Shinya Kitaoka 120a6e
    , m_frame(frame)
Shinya Kitaoka 120a6e
    , m_whichLevels(whichLevels)
Shinya Kitaoka 120a6e
    , m_isPreview(isPreview)
Shinya Kitaoka 120a6e
    , m_expandXSheet(expandXSheet)
Shinya Kitaoka 120a6e
    , m_particleDescendentCount(0) {
Shinya Kitaoka 120a6e
  TStageObjectId cameraId;
Shinya Kitaoka 120a6e
  if (m_isPreview)
Shinya Kitaoka 120a6e
    cameraId = m_xsh->getStageObjectTree()->getCurrentPreviewCameraId();
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    cameraId = m_xsh->getStageObjectTree()->getCurrentCameraId();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TStageObject *camera = m_xsh->getStageObject(cameraId);
Shinya Kitaoka 120a6e
  m_cameraAff          = camera->getPlacement(m_frame);
Shinya Kitaoka 120a6e
  m_cameraZ            = camera->getZ(m_frame);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFxP FxBuilder::buildFx() {
Shinya Kitaoka 120a6e
  TFx *outputFx = m_xsh->getFxDag()->getOutputFx(0);
Shinya Kitaoka 120a6e
  if (!outputFx || outputFx->getInputPortCount() != 1 ||
Shinya Kitaoka 120a6e
      outputFx->getInputPort(0)->getFx() == 0)
Shinya Kitaoka 120a6e
    return TFxP();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  outputFx->setName(L"OutputFx");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(m_particleDescendentCount == 0);
Shinya Kitaoka 120a6e
  PlacedFx pf = makePF(outputFx->getInputPort(0)->getFx());
Shinya Kitaoka 120a6e
  assert(m_particleDescendentCount == 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TAffine cameraFullAff = m_cameraAff * TScale((1000 + m_cameraZ) / 1000);
Shinya Kitaoka 120a6e
  return TFxUtil::makeAffine(pf.makeFx(), cameraFullAff.inv());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFxP FxBuilder::buildFx(const TFxP &root, BSFX_Transforms_Enum transforms) {
Shinya Kitaoka 120a6e
  assert(m_particleDescendentCount == 0);
Shinya Kitaoka 120a6e
  PlacedFx pf = makePF(root.getPointer());
Shinya Kitaoka 120a6e
  assert(m_particleDescendentCount == 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFxP fx = (transforms & BSFX_COLUMN_TR) ? pf.makeFx() : pf.m_fx;
Shinya Kitaoka 120a6e
  if (transforms & BSFX_CAMERA_TR) {
Shinya Kitaoka 120a6e
    TAffine cameraFullAff = m_cameraAff * TScale((1000 + m_cameraZ) / 1000);
Shinya Kitaoka 120a6e
    fx                    = TFxUtil::makeAffine(fx, cameraFullAff.inv());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return fx;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFxP FxBuilder::getFxWithColumnMovements(const PlacedFx &pf) {
Shinya Kitaoka 120a6e
  TFxP fx = pf.m_fx;
Shinya Kitaoka 120a6e
  if (!fx) return fx;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (pf.m_columnIndex == -1) return pf.m_fx;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TStageObjectId id    = TStageObjectId::ColumnId(pf.m_columnIndex);
Shinya Kitaoka 120a6e
  TStageObject *pegbar = m_xsh->getStageObject(id);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  AffineFx *affFx = new AffineFx(m_xsh, pegbar);
Shinya Kitaoka 120a6e
  affFx->getInputPort(0)->setFx(fx.getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return affFx;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool FxBuilder::addPlasticDeformerFx(PlacedFx &pf) {
Shinya Kitaoka 120a6e
  TStageObject *obj =
Shinya Kitaoka 120a6e
      m_xsh->getStageObject(TStageObjectId::ColumnId(pf.m_columnIndex));
Shinya Kitaoka 120a6e
  TStageObjectId parentId(obj->getParent());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (parentId.isColumn() && obj->getParentHandle()[0] != 'H') {
Shinya Kitaoka 120a6e
    const SkDP &sd =
Shinya Kitaoka 120a6e
        m_xsh->getStageObject(parentId)->getPlasticSkeletonDeformation();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    const TXshCell &parentCell = m_xsh->getCell(m_frame, parentId.getIndex());
Shinya Kitaoka 120a6e
    TXshSimpleLevel *parentSl  = parentCell.getSimpleLevel();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (sd && parentSl && (parentSl->getType() == MESH_XSHLEVEL)) {
Shinya Kitaoka 120a6e
      // Plastic Deformer case - add the corresponding fx,
Shinya Kitaoka 120a6e
      // absorb the dpi and local column placement affines
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      PlasticDeformerFx *plasticFx = new PlasticDeformerFx;
Shinya Kitaoka 120a6e
      plasticFx->m_xsh             = m_xsh;
Shinya Kitaoka 120a6e
      plasticFx->m_col             = parentId.getIndex();
Shinya Kitaoka 120a6e
      plasticFx->m_texPlacement    = obj->getLocalPlacement(m_frame);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      if (!plasticFx->connect("source", pf.m_fx.getPointer()))
Shinya Kitaoka 120a6e
        assert(!"Could not connect ports!");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      pf.m_fx  = plasticFx;
Shinya Kitaoka 120a6e
      pf.m_aff = pf.m_aff * plasticFx->m_texPlacement.inv();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      return true;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
PlacedFx FxBuilder::makePF(TFx *fx) {
Shinya Kitaoka 120a6e
  if (!fx) return PlacedFx();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (TLevelColumnFx *lcfx = dynamic_cast<tlevelcolumnfx *="">(fx))</tlevelcolumnfx>
Shinya Kitaoka 120a6e
    return makePF(lcfx);
Shinya Kitaoka 120a6e
  else if (TPaletteColumnFx *pcfx = dynamic_cast<tpalettecolumnfx *="">(fx))</tpalettecolumnfx>
Shinya Kitaoka 120a6e
    return makePF(pcfx);
Shinya Kitaoka 120a6e
  else if (TZeraryColumnFx *zcfx = dynamic_cast<tzerarycolumnfx *="">(fx))</tzerarycolumnfx>
Shinya Kitaoka 120a6e
    return makePF(zcfx);
Shinya Kitaoka 120a6e
  else if (TXsheetFx *xsfx = dynamic_cast<txsheetfx *="">(fx))</txsheetfx>
Shinya Kitaoka 120a6e
    return makePF(xsfx);
Shinya Kitaoka 120a6e
  else if (fx->getInputPortCount() == 1)
Shinya Kitaoka 120a6e
    return makePFfromUnaryFx(fx);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return makePFfromGenericFx(fx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
PlacedFx FxBuilder::makePF(TXsheetFx *fx) {
Shinya Kitaoka 120a6e
  if (!m_expandXSheet)  // Xsheet expansion is typically blocked for render-tree
Shinya Kitaoka 120a6e
                        // building of
Shinya Kitaoka 120a6e
    return PlacedFx(fx);  // post-xsheet fxs only.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Expand the render-tree from terminal fxs
Shinya Kitaoka 120a6e
  TFxSet *fxs = m_xsh->getFxDag()->getTerminalFxs();
Shinya Kitaoka 120a6e
  int m       = fxs->getFxCount();
Shinya Kitaoka 120a6e
  if (m == 0) return PlacedFx();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<placedfx> pfs(m);</placedfx>
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < m; i++) {
Shinya Kitaoka 120a6e
    // Expand each terminal fx
Shinya Kitaoka 120a6e
    TFx *fx = fxs->getFx(i);
Shinya Kitaoka 120a6e
    assert(fx);
Shinya Kitaoka 120a6e
    pfs[i] = makePF(fx);  // Builds the sub-render-trees here
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*--
Shinya Kitaoka 120a6e
   * Xsheetに複数ノードが繋がっていた場合、PlacedFxの条件に従ってOverノードの付く順番を決める
Shinya Kitaoka 120a6e
   * --*/
Shinya Kitaoka 120a6e
  std::sort(pfs.begin(),
Shinya Kitaoka 120a6e
            pfs.end());  // Sort each terminal depending on Z/SO/Column index
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Compose them in a cascade of overs (or affines 'leftXsheetPort' cases)
Shinya Kitaoka 120a6e
  TFxP currentFx =
Shinya Kitaoka 120a6e
      pfs[0].makeFx();  // Adds an NaAffineFx if pf.m_aff is not the identity
Shinya Kitaoka 120a6e
  for (i = 1; i < m; i++) {
Shinya Kitaoka 120a6e
    TFxP fx = pfs[i].makeFx();  // See above
Shinya Kitaoka 120a6e
    if (pfs[i].m_leftXsheetPort) {
Shinya Kitaoka 120a6e
      // LeftXsheetPort cases happen for those fxs like Add, Multiply, etc that
Shinya Kitaoka 120a6e
      // declare an xsheet-like input port.
Shinya Kitaoka 120a6e
      // That is, all terminal fxs below ours are attached COMPOSED to enter the
Shinya Kitaoka 120a6e
      // fx's leftXsheet input port.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TFxP inputFx = currentFx;
Shinya Kitaoka 120a6e
      inputFx      = TFxUtil::makeAffine(inputFx, pfs[i].m_aff.inv());
Shinya Kitaoka 120a6e
      pfs[i].m_leftXsheetPort->setFx(inputFx.getPointer());
Shinya Kitaoka 120a6e
      currentFx = fx;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      if (Preferences::instance()
Shinya Kitaoka 120a6e
              ->isShowRasterImagesDarkenBlendedInViewerEnabled())
Shinya Kitaoka 120a6e
        currentFx = TFxUtil::makeDarken(currentFx, fx);
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        currentFx = TFxUtil::makeOver(currentFx, fx);  // Common over case
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return PlacedFx(currentFx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Creates and returns a PlacedFx for a TLevelColumnFx.
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
  Fxs under a ParticlesFx node seem to have special treatment - that is,
Toshihiro Shimizu 890ddd
  empty column cells are still attached to a not-empty PlacedFx.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  This must be a remnant of old Toonz code, that should no longer remain here -
Toshihiro Shimizu 890ddd
  in fact, well, you can only extract an empty render from an empty column!
Toshihiro Shimizu 890ddd
  So why bother?
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
PlacedFx FxBuilder::makePF(TLevelColumnFx *lcfx) {
Shinya Kitaoka 120a6e
  assert(m_scene);
Shinya Kitaoka 120a6e
  assert(lcfx);
Shinya Kitaoka 120a6e
  assert(lcfx->getColumn());
Shinya Kitaoka 120a6e
  if (!lcfx || !lcfx->getColumn()) return PlacedFx();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!lcfx->getColumn()->isPreviewVisible())  // This is the 'eye' icon
Shinya Kitaoka 120a6e
                                               // property in the column header
Shinya Kitaoka 120a6e
                                               // interface
Shinya Kitaoka 120a6e
    return PlacedFx();  // that disables rendering of this particular column
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Retrieve the corresponding xsheet cell to build up
Shinya Kitaoka 120a6e
  /*-- 現在のフレームのセルを取得 --*/
Shinya Kitaoka 120a6e
  TXshCell cell  = lcfx->getColumn()->getCell(tfloor(m_frame));
Shinya Kitaoka 120a6e
  int levelFrame = cell.m_frameId.getNumber() - 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*--  ParticlesFxに繋がっておらず、空セルの場合は 中身無しを返す --*/
Shinya Kitaoka 120a6e
  if (m_particleDescendentCount == 0 && cell.isEmpty()) return PlacedFx();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_whichLevels == TOutputProperties::AnimatedOnly) {
Shinya Kitaoka 120a6e
    // In case only 'animated levels' are selected to be rendered, exclude all
Shinya Kitaoka 120a6e
    // 'backgrounds' - that is,
Shinya Kitaoka 120a6e
    // fullcolor levels...
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Still, I wonder if this is still used in Toonz. I don't remember seeing
Shinya Kitaoka 120a6e
    // it anywhere :\ ?
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TXshLevel *xl = cell.m_level.getPointer();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    /*-- ParticleFxのTextureポートに繋がっていない場合 --*/
Shinya Kitaoka 120a6e
    if (m_particleDescendentCount == 0) {
Shinya Kitaoka 120a6e
      if (!xl ||
Rozhuk Ivan 823a31
          (xl->getType() != PLI_XSHLEVEL && xl->getType() != TZP_XSHLEVEL &&
Jeremy Bullock 852210
           xl->getType() != CHILD_XSHLEVEL))
Shinya Kitaoka 120a6e
        return PlacedFx();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    /*-- ParticleFxのTextureポートに繋がっている場合 --*/
Shinya Kitaoka 120a6e
    else {
Shinya Kitaoka 120a6e
      if (xl && xl->getType() != PLI_XSHLEVEL &&
Shinya Kitaoka 120a6e
          xl->getType() != TZP_XSHLEVEL && xl->getType() != CHILD_XSHLEVEL)
Shinya Kitaoka 120a6e
        return PlacedFx();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build a PlacedFx for the column - start with the standard version for
Shinya Kitaoka 120a6e
  // common (image) levels
Shinya Kitaoka 120a6e
  PlacedFx pf;
Shinya Kitaoka 120a6e
  pf.m_columnIndex = lcfx->getColumn()->getIndex();
Shinya Kitaoka 120a6e
  pf.m_fx          = lcfx;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build column placement
Shinya Kitaoka 120a6e
  bool columnVisible =
Shinya Kitaoka 120a6e
      getColumnPlacement(pf, m_xsh, m_frame, pf.m_columnIndex, m_isPreview);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*-- subXsheetのとき、その中身もBuildFxを実行 --*/
Shinya Kitaoka 120a6e
  if (!cell.isEmpty() && cell.m_level->getChildLevel()) {
Shinya Kitaoka 120a6e
    // Treat the sub-xsheet case - build the sub-render-tree and reassign stuff
Shinya Kitaoka 120a6e
    // to pf
Shinya Kitaoka 120a6e
    TXsheet *xsh = cell.m_level->getChildLevel()->getXsheet();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Build the sub-render-tree
Shinya Kitaoka 120a6e
    FxBuilder builder(m_scene, xsh, levelFrame, m_whichLevels, m_isPreview);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Then, add the TimeShuffleFx
shun-iwasawa 0b8813
    pf.m_fx = timeShuffle(builder.buildFx(), levelFrame, lcfx->getTimeRegion(),
shun-iwasawa 0b8813
                          lcfx->getColumn());
Shinya Kitaoka 120a6e
    pf.m_fx->setIdentifier(lcfx->getIdentifier());
Shinya Kitaoka 120a6e
    pf.m_fx->getAttributes()->passiveCacheDataIdx() =
Shinya Kitaoka 120a6e
        lcfx->getAttributes()->passiveCacheDataIdx();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // If the level should sustain a Plastic deformation, add the corresponding
Shinya Kitaoka 120a6e
    // fx
Shinya Kitaoka 120a6e
    addPlasticDeformerFx(pf);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (columnVisible) {
Shinya Kitaoka 120a6e
    // Column is visible, alright
Shinya Kitaoka 120a6e
    TXshSimpleLevel *sl = cell.isEmpty() ? 0 : cell.m_level->getSimpleLevel();
Shinya Kitaoka 120a6e
    if (sl) {
Shinya Kitaoka 120a6e
      // If the level should sustain a Plastic deformation, add the
Shinya Kitaoka 120a6e
      // corresponding fx
Shinya Kitaoka 120a6e
      if (!addPlasticDeformerFx(pf)) {
Shinya Kitaoka 120a6e
        // Common (image) level case - add an NaAffineFx to compensate for the
Shinya Kitaoka 120a6e
        // image's dpi
Shinya Kitaoka 120a6e
        TAffine dpiAff = ::getDpiAffine(
Shinya Kitaoka 120a6e
            sl, cell.m_frameId, true);  // true stands for 'force full-sampling'
Shinya Kitaoka 120a6e
        pf.m_fx = TFxUtil::makeAffine(pf.m_fx, dpiAff);
Shinya Kitaoka 120a6e
        if (pf.m_fx) pf.m_fx->setName(L"LevelColumn AffineFx");
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      // Okay, weird code ensues. This is what happens on non-common image
Shinya Kitaoka 120a6e
      // cases, which should be:
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      //  1. Sub-Xsheet cases - and it really shouldn't
Shinya Kitaoka 120a6e
      //  2. Empty cell cases - with m_particles_blabla > 0; and again I don't
Shinya Kitaoka 120a6e
      //  get why on earth this should happen...
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Please, note that (1) is a bug, although it happens when inserting a
Shinya Kitaoka 120a6e
      // common level and a sub-xsh
Shinya Kitaoka 120a6e
      // level in the same column...
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // when a cell not exists, there is no way to keep the dpi of the image!
Shinya Kitaoka 120a6e
      // in this case it is kept the dpi of the first cell not empty in the
Shinya Kitaoka 120a6e
      // column!
Shinya Kitaoka 120a6e
      /*--
Shinya Kitaoka 120a6e
       * 空セルのとき、Dpiアフィン変換には、その素材が入っている一番上のセルのものを使う
Shinya Kitaoka 120a6e
       * --*/
Shinya Kitaoka 120a6e
      TXshLevelColumn *column = lcfx->getColumn();
Shinya Kitaoka 120a6e
      int i;
Shinya Kitaoka 120a6e
      for (i = 0; i < column->getRowCount(); i++) {
Shinya Kitaoka 120a6e
        TXshCell dpiCell = lcfx->getColumn()->getCell(i);
Shinya Kitaoka 120a6e
        if (dpiCell.isEmpty()) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        sl = dpiCell.m_level->getSimpleLevel();
Shinya Kitaoka 120a6e
        if (!sl) break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        TAffine dpiAff = ::getDpiAffine(sl, dpiCell.m_frameId, true);
Shinya Kitaoka 120a6e
        pf.m_fx        = TFxUtil::makeAffine(pf.m_fx, dpiAff);
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
shun_iwasawa 2c0f50
    // Apply column's color filter and semi-transparency for rendering
shun_iwasawa 2c0f50
    TXshLevelColumn *column = lcfx->getColumn();
shun_iwasawa 2c0f50
    if (m_scene->getProperties()->isColumnColorFilterOnRenderEnabled() &&
shun_iwasawa 2c0f50
        (column->getFilterColorId() != TXshColumn::FilterNone ||
shun_iwasawa 2c0f50
         (column->isCamstandVisible() && column->getOpacity() != 255))) {
shun_iwasawa 2c0f50
      TPixel32 colorScale = column->getFilterColor();
shun_iwasawa 2c0f50
      colorScale.m        = column->getOpacity();
shun_iwasawa 2c0f50
      pf.m_fx             = TFxUtil::makeColumnColorFilter(pf.m_fx, colorScale);
shun_iwasawa 2c0f50
    }
shun_iwasawa 2c0f50
Shinya Kitaoka 120a6e
    return pf;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    return PlacedFx();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
PlacedFx FxBuilder::makePF(TPaletteColumnFx *pcfx) {
Shinya Kitaoka 120a6e
  assert(pcfx);
Shinya Kitaoka 120a6e
  assert(pcfx->getColumn());
Shinya Kitaoka 120a6e
  if (!pcfx->getColumn()->isPreviewVisible()) return PlacedFx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXshCell cell = pcfx->getColumn()->getCell(tfloor(m_frame));
Shinya Kitaoka 120a6e
  if (cell.isEmpty()) return PlacedFx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  PlacedFx pf;
Shinya Kitaoka 120a6e
  pf.m_columnIndex = pcfx->getColumn()->getIndex();
Shinya Kitaoka 120a6e
  pf.m_fx          = pcfx;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return pf;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
PlacedFx FxBuilder::makePF(TZeraryColumnFx *zcfx) {
Shinya Kitaoka 120a6e
  assert(zcfx);
Shinya Kitaoka 120a6e
  assert(zcfx->getColumn());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!zcfx->getColumn()->isPreviewVisible())  // ...
Shinya Kitaoka 120a6e
    return PlacedFx();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!zcfx->getAttributes()->isEnabled())  // ...
Shinya Kitaoka 120a6e
    return PlacedFx();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFx *fx = zcfx->getZeraryFx();
Shinya Kitaoka 120a6e
  if (!fx || !fx->getAttributes()->isEnabled())  // ... Perhaps these shouldn't
Shinya Kitaoka 120a6e
                                                 // be tested altogether? Only 1
Shinya Kitaoka 120a6e
                                                 // truly works !
Shinya Kitaoka 120a6e
    return PlacedFx();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXshCell cell = zcfx->getColumn()->getCell(tfloor(m_frame));
Shinya Kitaoka 120a6e
  if (cell.isEmpty()) return PlacedFx();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build
Shinya Kitaoka 120a6e
  PlacedFx pf;
Shinya Kitaoka 120a6e
  pf.m_columnIndex = zcfx->getColumn()->getIndex();
shun-iwasawa 0b8813
  pf.m_fx =
shun-iwasawa 0b8813
      fx->clone(false);  // Detach the fx with a clone. Why? It's typically done
shun-iwasawa 0b8813
                         // to build fx connections in the render-tree freely.
shun-iwasawa 0b8813
                         // Here, it's used just for particles, I guess...
Shinya Kitaoka 120a6e
  // Deal with input sub-trees
Shinya Kitaoka 120a6e
  for (int i = 0; i < fx->getInputPortCount(); ++i) {
Shinya Kitaoka 120a6e
    // Note that only particles should end up here, currently
Shinya Kitaoka 120a6e
    if (TFxP inputFx = fx->getInputPort(i)->getFx()) {
Shinya Kitaoka 120a6e
      PlacedFx inputPF;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // if the effect is a particle fx, it is necessary to consider also empty
Shinya Kitaoka 120a6e
      // cells
Shinya Kitaoka 120a6e
      // this causes a connection with the effect and a level also with empty
Shinya Kitaoka 120a6e
      // cells.
Shinya Kitaoka 120a6e
      if (fx->getFxType() == "STD_particlesFx" ||
Shinya Kitaoka 120a6e
          fx->getFxType() == "STD_iwa_TiledParticlesFx" ||
Shinya Kitaoka 120a6e
          fx->getFxType() == "STD_tiledParticlesFx") {
Shinya Kitaoka 120a6e
        m_particleDescendentCount++;
Shinya Kitaoka 120a6e
        inputPF = makePF(inputFx.getPointer());
Shinya Kitaoka 120a6e
        m_particleDescendentCount--;
Shinya Kitaoka 120a6e
      } else
Shinya Kitaoka 120a6e
        inputPF = makePF(inputFx.getPointer());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      inputFx = getFxWithColumnMovements(inputPF);
Shinya Kitaoka 120a6e
      if (!inputFx) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      inputFx = TFxUtil::makeAffine(inputFx, pf.m_aff.inv());
Shinya Kitaoka 120a6e
      if (!pf.m_fx->connect(pf.m_fx->getInputPortName(i), inputFx.getPointer()))
Shinya Kitaoka 120a6e
        assert(!"Could not connect ports!");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
shun-iwasawa 5b2332
  if (pf.m_fx->getFxType() == "STD_iwa_TextFx") {
shun-iwasawa 5b2332
    TextAwareBaseFx *textFx =
shun-iwasawa 5b2332
        dynamic_cast<textawarebasefx *="">(pf.m_fx.getPointer());</textawarebasefx>
shun-iwasawa 5b2332
    if (textFx && textFx->getSourceType() != TextAwareBaseFx::INPUT_TEXT) {
shun-iwasawa 5b2332
      int noteColumnIndex = textFx->getNoteColumnIndex();
shun-iwasawa 5b2332
      bool getNeighbor =
shun-iwasawa 5b2332
          (textFx->getSourceType() == TextAwareBaseFx::NEARBY_COLUMN);
shun-iwasawa 5b2332
      textFx->setNoteLevelStr(getNoteText(m_xsh, m_frame, pf.m_columnIndex,
shun-iwasawa 5b2332
                                          noteColumnIndex, getNeighbor));
shun-iwasawa 5b2332
    }
shun-iwasawa 5b2332
  }
shun-iwasawa 5b2332
Shinya Kitaoka 120a6e
  // Add the column placement NaAffineFx
Shinya Kitaoka 120a6e
  if (getColumnPlacement(pf, m_xsh, m_frame, pf.m_columnIndex, m_isPreview))
Shinya Kitaoka 120a6e
    return pf;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return PlacedFx();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
PlacedFx FxBuilder::makePFfromUnaryFx(TFx *fx) {
Shinya Kitaoka 120a6e
  assert(!dynamic_cast<tlevelcolumnfx *="">(fx));</tlevelcolumnfx>
Shinya Kitaoka 120a6e
  assert(!dynamic_cast<tzerarycolumnfx *="">(fx));</tzerarycolumnfx>
Shinya Kitaoka 120a6e
  assert(fx->getInputPortCount() == 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFx *inputFx = fx->getInputPort(0)->getFx();
Shinya Kitaoka 120a6e
  if (!inputFx) return PlacedFx();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  PlacedFx pf = makePF(inputFx);  // Build sub-render-tree
Shinya Kitaoka 120a6e
  if (!pf.m_fx) return PlacedFx();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (fx->getAttributes()->isEnabled()) {
Shinya Kitaoka 120a6e
    // Fx is enabled, so insert it in the render-tree
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Clone this fx necessary
Shinya Kitaoka 120a6e
    if (pf.m_fx.getPointer() != inputFx ||  // As in an earlier makePF, clone
Shinya Kitaoka 120a6e
                                            // whenever input connections have
Shinya Kitaoka 120a6e
                                            // changed
Shinya Kitaoka 120a6e
        fx->getAttributes()->isSpeedAware() ||  // In the 'speedAware' case,
Shinya Kitaoka 120a6e
                                                // we'll alter the fx's
Shinya Kitaoka 120a6e
                                                // attributes (see below)
Shinya Kitaoka 120a6e
        dynamic_cast<tmacrofx *="">(fx))  // As for macros... I'm not sure. Not</tmacrofx>
Shinya Kitaoka 120a6e
                                       // even who wrote this *understood*
Shinya Kitaoka 120a6e
    // why - it just solved a bug  X( . Investigate!
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      fx = fx->clone(false);
Shinya Kitaoka 120a6e
      if (!fx->connect(fx->getInputPortName(0), pf.m_fx.getPointer()))
Shinya Kitaoka 120a6e
        assert(!"Could not connect ports!");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    pf.m_fx = fx;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (fx->getAttributes()->isSpeedAware()) {
Shinya Kitaoka 120a6e
      /*-- スピードでなく、軌跡を取得する場合 --*/
Shinya Kitaoka 120a6e
      MotionAwareBaseFx *mabfx = dynamic_cast<motionawarebasefx *="">(fx);</motionawarebasefx>
Shinya Kitaoka 120a6e
      if (mabfx) {
Shinya Kitaoka 120a6e
        double shutterStart = mabfx->getShutterStart()->getValue(m_frame);
Shinya Kitaoka 120a6e
        double shutterEnd   = mabfx->getShutterEnd()->getValue(m_frame);
Shinya Kitaoka 120a6e
        int traceResolution = mabfx->getTraceResolution()->getValue();
Shinya Kitaoka 120a6e
        /*-- 移動の参考にするオブジェクトの取得。自分自身の場合はNoneId --*/
Shinya Kitaoka 120a6e
        MotionObjectType type   = mabfx->getMotionObjectType();
Shinya Kitaoka 120a6e
        int index               = mabfx->getMotionObjectIndex()->getValue();
Shinya Kitaoka 120a6e
        TStageObjectId objectId = getMotionObjectId(type, index);
Shinya Kitaoka 120a6e
        fx->getAttributes()->setMotionPoints(getColumnMotionPoints(
Shinya Kitaoka 120a6e
            m_xsh, m_frame, pf.m_columnIndex, objectId, m_isPreview,
Shinya Kitaoka 120a6e
            shutterStart, shutterEnd, traceResolution));
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        TPointD speed =
Shinya Kitaoka 120a6e
            getColumnSpeed(m_xsh, m_frame, pf.m_columnIndex, m_isPreview);
Shinya Kitaoka 120a6e
        fx->getAttributes()->setSpeed(speed);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return pf;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
PlacedFx FxBuilder::makePFfromGenericFx(TFx *fx) {
Shinya Kitaoka 120a6e
  assert(!dynamic_cast<tlevelcolumnfx *="">(fx));</tlevelcolumnfx>
Shinya Kitaoka 120a6e
  assert(!dynamic_cast<tzerarycolumnfx *="">(fx));</tzerarycolumnfx>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  PlacedFx pf;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!fx->getAttributes()->isEnabled()) {
Shinya Kitaoka 120a6e
    if (fx->getInputPortCount() == 0) return PlacedFx();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TFxP inputFx = fx->getInputPort(fx->getPreferredInputPort())->getFx();
Shinya Kitaoka 120a6e
    if (inputFx) return makePF(inputFx.getPointer());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    return pf;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Multi-input fxs are always cloned - since at least one of its input ports
Shinya Kitaoka 120a6e
  // will have an NaAffineFx
Shinya Kitaoka 120a6e
  // injected just before its actual input fx.
Shinya Kitaoka 120a6e
  pf.m_fx = fx->clone(false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool firstInput = true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int m = fx->getInputPortCount();
Shinya Kitaoka 120a6e
  for (int i = 0; i < m; ++i) {
Shinya Kitaoka 120a6e
    if (TFxP inputFx = fx->getInputPort(i)->getFx()) {
Shinya Kitaoka 120a6e
      PlacedFx inputPF = makePF(inputFx.getPointer());
Shinya Kitaoka 120a6e
      inputFx          = inputPF.m_fx;
Shinya Kitaoka 120a6e
      if (!inputFx) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (firstInput) {
Shinya Kitaoka 120a6e
        firstInput = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // The first found input PlacedFx carries its placement infos up
Shinya Kitaoka 120a6e
        pf.m_aff         = inputPF.m_aff;
Shinya Kitaoka 120a6e
        pf.m_columnIndex = inputPF.m_columnIndex;
Shinya Kitaoka 120a6e
        pf.m_z           = inputPF.m_z;
Shinya Kitaoka 120a6e
        pf.m_so          = inputPF.m_so;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        /*-- 軌跡を取得するBinaryFxの場合 --*/
Shinya Kitaoka 120a6e
        if (pf.m_fx->getAttributes()->isSpeedAware()) {
shun-iwasawa a048bc
          MotionAwareBaseFx *mabfx =
shun-iwasawa a048bc
              dynamic_cast<motionawarebasefx *="">(pf.m_fx.getPointer());</motionawarebasefx>
Shinya Kitaoka 120a6e
          if (mabfx) {
Shinya Kitaoka 120a6e
            double shutterStart = mabfx->getShutterStart()->getValue(m_frame);
Shinya Kitaoka 120a6e
            double shutterEnd   = mabfx->getShutterEnd()->getValue(m_frame);
Shinya Kitaoka 120a6e
            int traceResolution = mabfx->getTraceResolution()->getValue();
Shinya Kitaoka 120a6e
            /*-- 移動の参考にするオブジェクトの取得。自分自身の場合はNoneId --*/
Shinya Kitaoka 120a6e
            MotionObjectType type   = mabfx->getMotionObjectType();
Shinya Kitaoka 120a6e
            int index               = mabfx->getMotionObjectIndex()->getValue();
Shinya Kitaoka 120a6e
            TStageObjectId objectId = getMotionObjectId(type, index);
shun-iwasawa a048bc
            pf.m_fx->getAttributes()->setMotionPoints(getColumnMotionPoints(
Shinya Kitaoka 120a6e
                m_xsh, m_frame, pf.m_columnIndex, objectId, m_isPreview,
Shinya Kitaoka 120a6e
                shutterStart, shutterEnd, traceResolution));
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        // The follow-ups traduce their PlacedFx::m_aff into an NaAffineFx,
Shinya Kitaoka 120a6e
        // instead
Shinya Kitaoka 120a6e
        inputFx = getFxWithColumnMovements(inputPF);
Shinya Kitaoka 120a6e
        inputFx = TFxUtil::makeAffine(inputFx, pf.m_aff.inv());
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (!pf.m_fx->connect(pf.m_fx->getInputPortName(i), inputFx.getPointer()))
Shinya Kitaoka 120a6e
        assert(!"Could not connect ports!");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // The xsheet-like input port is activated and brought upwards whenever it is
Shinya Kitaoka 120a6e
  // both
Shinya Kitaoka 120a6e
  // specified by the fx, and there is no input fx attached to it.
Shinya Kitaoka 120a6e
  if (pf.m_fx->getXsheetPort() && pf.m_fx->getXsheetPort()->getFx() == 0)
Shinya Kitaoka 120a6e
    pf.m_leftXsheetPort = pf.m_fx->getXsheetPort();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return pf;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
//    Exported  Render-Tree building  functions
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFxP buildSceneFx(ToonzScene *scene, TXsheet *xsh, double row, int whichLevels,
Shinya Kitaoka 120a6e
                  int shrink, bool isPreview) {
Shinya Kitaoka 120a6e
  FxBuilder builder(scene, xsh, row, whichLevels, isPreview);
Shinya Kitaoka 120a6e
  TFxP fx = builder.buildFx();
Shinya Kitaoka 120a6e
  TStageObjectId cameraId;
Shinya Kitaoka 120a6e
  if (isPreview)
Shinya Kitaoka 120a6e
    cameraId = xsh->getStageObjectTree()->getCurrentPreviewCameraId();
Shinya Kitaoka 120a6e
  else
shun-iwasawa 0b8813
    cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
Shinya Kitaoka 120a6e
  TStageObject *cameraPegbar = xsh->getStageObject(cameraId);
Shinya Kitaoka 120a6e
  assert(cameraPegbar);
Shinya Kitaoka 120a6e
  TCamera *camera = cameraPegbar->getCamera();
Shinya Kitaoka 120a6e
  assert(camera);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TAffine aff = getDpiAffine(camera).inv();
Shinya Kitaoka 120a6e
  if (shrink > 1) {
Shinya Kitaoka 120a6e
    double fac = 0.5 * (1.0 / shrink - 1.0);
Shinya Kitaoka 120a6e
    aff = TTranslation(fac * camera->getRes().lx, fac * camera->getRes().ly) *
Shinya Kitaoka 120a6e
          TScale(1.0 / shrink) * aff;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  fx = TFxUtil::makeAffine(fx, aff);
Shinya Kitaoka 120a6e
  if (fx) fx->setName(L"CameraDPI and Shrink NAffineFx");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  fx = TFxUtil::makeOver(
Shinya Kitaoka 120a6e
      TFxUtil::makeColorCard(scene->getProperties()->getBgColor()), fx);
Shinya Kitaoka 120a6e
  return fx;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFxP buildSceneFx(ToonzScene *scene, TXsheet *xsh, double row, int shrink,
Shinya Kitaoka 120a6e
                  bool isPreview) {
Shinya Kitaoka 120a6e
  int whichLevels =
Shinya Kitaoka 120a6e
      scene->getProperties()->getOutputProperties()->getWhichLevels();
Shinya Kitaoka 120a6e
  return buildSceneFx(scene, xsh, row, whichLevels, shrink, isPreview);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFxP buildSceneFx(ToonzScene *scene, double row, int shrink, bool isPreview) {
Shinya Kitaoka 120a6e
  return buildSceneFx(scene, scene->getXsheet(), row, shrink, isPreview);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFxP buildSceneFx(ToonzScene *scene, TXsheet *xsh, double row, const TFxP &root,
Shinya Kitaoka 120a6e
                  bool isPreview) {
Shinya Kitaoka 120a6e
  int whichLevels =
Shinya Kitaoka 120a6e
      scene->getProperties()->getOutputProperties()->getWhichLevels();
Shinya Kitaoka 120a6e
  FxBuilder builder(scene, xsh, row, whichLevels, isPreview);
Shinya Kitaoka 120a6e
  return builder.buildFx(root, BSFX_NO_TR);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFxP buildSceneFx(ToonzScene *scene, double row, const TFxP &root,
Shinya Kitaoka 120a6e
                  bool isPreview) {
Shinya Kitaoka 120a6e
  return buildSceneFx(scene, scene->getXsheet(), row, root, isPreview);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Similar to buildSceneFx(ToonzScene *scene, double row, const TFxP &root,
Shinya Kitaoka 120a6e
//! bool isPreview) method, build the sceneFx
Toshihiro Shimizu 890ddd
//! adding also camera transformations. Used for Preview Fx function.
Shinya Kitaoka 120a6e
DVAPI TFxP buildPartialSceneFx(ToonzScene *scene, double row, const TFxP &root,
Shinya Kitaoka 120a6e
                               int shrink, bool isPreview) {
Shinya Kitaoka 120a6e
  int whichLevels =
Shinya Kitaoka 120a6e
      scene->getProperties()->getOutputProperties()->getWhichLevels();
Shinya Kitaoka 120a6e
  FxBuilder builder(scene, scene->getXsheet(), row, whichLevels, isPreview);
Shinya Kitaoka 120a6e
  TFxP fx = builder.buildFx(
Shinya Kitaoka 120a6e
      root, BSFX_Transforms_Enum(BSFX_CAMERA_TR | BSFX_COLUMN_TR));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXsheet *xsh = scene->getXsheet();
Shinya Kitaoka 120a6e
  TStageObjectId cameraId;
Shinya Kitaoka 120a6e
  if (isPreview)
Shinya Kitaoka 120a6e
    cameraId = xsh->getStageObjectTree()->getCurrentPreviewCameraId();
Shinya Kitaoka 120a6e
  else
shun-iwasawa 0b8813
    cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
Shinya Kitaoka 120a6e
  TStageObject *cameraPegbar = xsh->getStageObject(cameraId);
Shinya Kitaoka 120a6e
  assert(cameraPegbar);
Shinya Kitaoka 120a6e
  TCamera *camera = cameraPegbar->getCamera();
Shinya Kitaoka 120a6e
  assert(camera);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TAffine aff = getDpiAffine(camera).inv();
Shinya Kitaoka 120a6e
  if (shrink > 1) {
Shinya Kitaoka 120a6e
    double fac = 0.5 * (1.0 / shrink - 1.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    aff = TTranslation(fac * camera->getRes().lx, fac * camera->getRes().ly) *
Shinya Kitaoka 120a6e
          TScale(1.0 / shrink) * aff;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  fx = TFxUtil::makeAffine(fx, aff);
Shinya Kitaoka 120a6e
  return fx;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DVAPI TFxP buildPartialSceneFx(ToonzScene *scene, TXsheet *xsheet, double row,
Shinya Kitaoka 120a6e
                               const TFxP &root, int shrink, bool isPreview) {
Shinya Kitaoka 120a6e
  int whichLevels =
Shinya Kitaoka 120a6e
      scene->getProperties()->getOutputProperties()->getWhichLevels();
Shinya Kitaoka 120a6e
  FxBuilder builder(scene, xsheet, row, whichLevels, isPreview);
Shinya Kitaoka 120a6e
  TFxP fx = builder.buildFx(
Shinya Kitaoka 120a6e
      root, BSFX_Transforms_Enum(BSFX_CAMERA_TR | BSFX_COLUMN_TR));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TStageObjectId cameraId;
Shinya Kitaoka 120a6e
  if (isPreview)
Shinya Kitaoka 120a6e
    cameraId = xsheet->getStageObjectTree()->getCurrentPreviewCameraId();
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    cameraId = xsheet->getStageObjectTree()->getCurrentCameraId();
Shinya Kitaoka 120a6e
  TStageObject *cameraPegbar = xsheet->getStageObject(cameraId);
Shinya Kitaoka 120a6e
  assert(cameraPegbar);
Shinya Kitaoka 120a6e
  TCamera *camera = cameraPegbar->getCamera();
Shinya Kitaoka 120a6e
  assert(camera);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TAffine aff = getDpiAffine(camera).inv();
Shinya Kitaoka 120a6e
  if (shrink > 1) {
Shinya Kitaoka 120a6e
    double fac = 0.5 * (1.0 / shrink - 1.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    aff = TTranslation(fac * camera->getRes().lx, fac * camera->getRes().ly) *
Shinya Kitaoka 120a6e
          TScale(1.0 / shrink) * aff;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  fx = TFxUtil::makeAffine(fx, aff);
Shinya Kitaoka 120a6e
  return fx;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*!
Shinya Kitaoka 120a6e
  Builds the post-rendering fxs tree - that is, all fxs between the xsheet node
Shinya Kitaoka 120a6e
  and
Toshihiro Shimizu 890ddd
  current output node.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  This function can be used to isolate global post-processing fxs that typically
Shinya Kitaoka 120a6e
  do not
Toshihiro Shimizu 890ddd
  contribute to scene compositing. When encountered, the xsheet node is \a not
Toshihiro Shimizu 890ddd
  xpanded - it must be replaced manually.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
DVAPI TFxP buildPostSceneFx(ToonzScene *scene, double frame, int shrink,
Shinya Kitaoka 120a6e
                            bool isPreview) {
Shinya Kitaoka 120a6e
  // NOTE: Should whichLevels access output AND PREVIEW settings?
Shinya Kitaoka 120a6e
  int whichLevels =
Shinya Kitaoka 120a6e
      scene->getProperties()->getOutputProperties()->getWhichLevels();
Toshihiro Shimizu 890ddd
shun-iwasawa 0b8813
  TXsheet *xsh = scene->getXsheet();
Shinya Kitaoka 120a6e
  if (!xsh) xsh = scene->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Do not expand the xsheet node
Shinya Kitaoka 120a6e
  FxBuilder builder(scene, xsh, frame, whichLevels, isPreview, false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFxP fx = builder.buildFx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TStageObjectId cameraId;
Shinya Kitaoka 120a6e
  if (isPreview)
Shinya Kitaoka 120a6e
    cameraId = xsh->getStageObjectTree()->getCurrentPreviewCameraId();
Shinya Kitaoka 120a6e
  else
shun-iwasawa 0b8813
    cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
Shinya Kitaoka 120a6e
  TStageObject *cameraPegbar = xsh->getStageObject(cameraId);
Shinya Kitaoka 120a6e
  assert(cameraPegbar);
Shinya Kitaoka 120a6e
  TCamera *camera = cameraPegbar->getCamera();
Shinya Kitaoka 120a6e
  assert(camera);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TAffine aff = getDpiAffine(camera).inv();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (shrink > 1) {
Shinya Kitaoka 120a6e
    double fac = 0.5 * (1.0 / shrink - 1.0);
Shinya Kitaoka 120a6e
    aff = TTranslation(fac * camera->getRes().lx, fac * camera->getRes().ly) *
Shinya Kitaoka 120a6e
          TScale(1.0 / shrink) * aff;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!aff.isIdentity()) fx = TFxUtil::makeAffine(fx, aff);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return fx;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DVAPI TFxP buildSceneFx(ToonzScene *scene, double frame, TXsheet *xsh,
Shinya Kitaoka 120a6e
                        const TFxP &root, BSFX_Transforms_Enum transforms,
Shinya Kitaoka 120a6e
                        bool isPreview, int whichLevels, int shrink) {
Shinya Kitaoka 120a6e
  // NOTE: Should whichLevels access output AND PREVIEW settings?
Shinya Kitaoka 120a6e
  if (whichLevels == -1)
Shinya Kitaoka 120a6e
    whichLevels =
Shinya Kitaoka 120a6e
        scene->getProperties()->getOutputProperties()->getWhichLevels();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!xsh) xsh = scene->getXsheet();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  FxBuilder builder(scene, xsh, frame, whichLevels, isPreview);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFxP fx = root ? builder.buildFx(root, transforms) : builder.buildFx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TStageObjectId cameraId =
Shinya Kitaoka 120a6e
      isPreview ? xsh->getStageObjectTree()->getCurrentPreviewCameraId()
Shinya Kitaoka 120a6e
                : xsh->getStageObjectTree()->getCurrentCameraId();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TStageObject *cameraPegbar = xsh->getStageObject(cameraId);
Shinya Kitaoka 120a6e
  assert(cameraPegbar);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TCamera *camera = cameraPegbar->getCamera();
Shinya Kitaoka 120a6e
  assert(camera);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TAffine aff;
Shinya Kitaoka 120a6e
  if (transforms & BSFX_CAMERA_DPI_TR) aff = getDpiAffine(camera).inv();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (shrink > 1) {
Shinya Kitaoka 120a6e
    double fac = 0.5 * (1.0 / shrink - 1.0);
Shinya Kitaoka 120a6e
    aff = TTranslation(fac * camera->getRes().lx, fac * camera->getRes().ly) *
Shinya Kitaoka 120a6e
          TScale(1.0 / shrink) * aff;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!aff.isIdentity()) fx = TFxUtil::makeAffine(fx, aff);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return fx;
Toshihiro Shimizu 890ddd
}