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