rework placement to contain a LUID, and to deal with inheritance according to the concept draft
This commit is contained in:
parent
0d41379dda
commit
efa7b4717c
11 changed files with 212 additions and 151 deletions
|
|
@ -113,8 +113,8 @@ namespace lib {
|
|||
|
||||
|
||||
/* === for use within unordered_map === */
|
||||
size_t hash_value (Plain const& plainHash) { return plainHash; }
|
||||
size_t hash_value (LuidH const& luid_Hash) { return luid_Hash; }
|
||||
inline size_t hash_value (Plain const& plainHash) { return plainHash; }
|
||||
inline size_t hash_value (LuidH const& luid_Hash) { return luid_Hash; }
|
||||
|
||||
} // namespace "hash"
|
||||
|
||||
|
|
|
|||
|
|
@ -116,6 +116,11 @@ namespace mobject {
|
|||
{
|
||||
currentWrapper_ = ptr_toWrappedTarget;
|
||||
}
|
||||
template<class TAR>
|
||||
void rememberWrapper (Placement<TAR>* ptr_toWrappedTarget)
|
||||
{
|
||||
currentWrapper_ = ptr_toWrappedTarget;
|
||||
}
|
||||
|
||||
void forgetWrapper ()
|
||||
{
|
||||
|
|
@ -153,7 +158,7 @@ namespace mobject {
|
|||
|
||||
|
||||
/**
|
||||
* declare the concrete types a BuilderTool may recievee and treat.
|
||||
* declare the concrete types a BuilderTool may receive and treat.
|
||||
* @note it is recommended to use ApplicableBuilderTargetTypes
|
||||
*/
|
||||
template
|
||||
|
|
|
|||
|
|
@ -26,34 +26,45 @@
|
|||
#include "proc/mobject/mobject.hpp"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
using boost::format;
|
||||
using boost::str;
|
||||
|
||||
namespace mobject
|
||||
{
|
||||
namespace mobject {
|
||||
|
||||
|
||||
template<class MO>
|
||||
ExplicitPlacement
|
||||
Placement<MO>::resolve () const
|
||||
{
|
||||
return ExplicitPlacement (*this, chain.resolve());
|
||||
}
|
||||
|
||||
/** @note we know we need only this single specialisation,
|
||||
* because we define the Placements of more specific
|
||||
* MObject kinds to be subclasses of Placement<MObject>,
|
||||
* so they will inherit this function.
|
||||
*/
|
||||
template ExplicitPlacement Placement<MObject>::resolve() const;
|
||||
|
||||
|
||||
ExplicitPlacement
|
||||
Placement<MObject>::resolve () const
|
||||
{
|
||||
return ExplicitPlacement (*this, chain.resolve());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<>
|
||||
Placement<MObject>::operator string () const
|
||||
{
|
||||
static boost::format fmt("Placement<%s> %|50T.| use-cnt=%x adr=%x pointee=%x");
|
||||
return str(fmt % typeid(*get()).name() % use_count() % this % get() );
|
||||
}
|
||||
{
|
||||
static format fmt("Placement<%s> %|50T.| use-cnt=%x ID(%x) adr=%x pointee=%x");
|
||||
return str(fmt % typeid(*get()).name() % use_count()
|
||||
% (size_t)getID()
|
||||
% this
|
||||
% get()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
string
|
||||
format_PlacementID (Placement<MObject> const& pla)
|
||||
{
|
||||
static format fmt ("pID(%x)");
|
||||
|
||||
size_t hashVal = pla.getID();
|
||||
return str(fmt % hashVal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
** Placements are at the very core of all editing operations,
|
||||
** because they act as handles to access the media objects to be manipulated.
|
||||
** Moreover, Placements are the actual content of the EDL(s) and Fixture and thus
|
||||
** are small objects with value semantics. Many editing tasks include locating some
|
||||
** Placement in the EDL or directly take a ref to a Placement.
|
||||
** are small handle like objects. Many editing tasks include locating some Placement
|
||||
** within the Session or directly take a ref to a Placement.
|
||||
**
|
||||
** Placements are <b>refcounting smart pointers</b>: By acting on the Placement object,
|
||||
** we can change parameters of the way the media object is placed (e.g. adjust an offset),
|
||||
|
|
@ -41,6 +41,17 @@
|
|||
** case of such constraining is to add a FixedLocation, thus placing the MObject at one
|
||||
** absolute position (time, track).
|
||||
**
|
||||
** Together, this yields semantics somewhere in between value semantics and reference semantics.
|
||||
** As any smart-ptr, placements are copyable, any such copies being considered equivalent. \em But,
|
||||
** when added to the Session, a placement acts as if it was an \em instance of the object it
|
||||
** points at, with the purpose to bind this instance into the Session with specific placement
|
||||
** properties. Thus, such a placement-within-session \em is an distinguishable entity, because
|
||||
** the settings on the contained LocatingPin chain \em do constitute the relation properties
|
||||
** of the MObject "placed" by this placement. To support this rather ref-like semantics, any
|
||||
** placement has an embedded ID (identity), and the Session won't allow to add a clone copy
|
||||
** of an placement with the same identity. Moreover, it is possible to create a smart-ptr
|
||||
** like PlacementRef to denote a specific placement found within the current Session.
|
||||
**
|
||||
** Placements are templated on the type of the actual MObject they refer to, so, sometimes
|
||||
** we rather use a Placement<Clip> to be able to use the more specific methods of the
|
||||
** session::Clip interface. But <i>please note the following detail:</i> this type
|
||||
|
|
@ -58,8 +69,10 @@
|
|||
#define MOBJECT_PLACEMENT_H
|
||||
|
||||
#include "pre.hpp"
|
||||
#include "lib/hash-indexed.hpp"
|
||||
#include "proc/mobject/session/locatingpin.hpp"
|
||||
#include "proc/asset/pipe.hpp"
|
||||
|
||||
#include "proc/asset/pipe.hpp" /////TODO: get rid of this (Trac #109)
|
||||
|
||||
#include <tr1/memory>
|
||||
|
||||
|
|
@ -68,25 +81,49 @@ namespace mobject {
|
|||
|
||||
namespace session{ class MObjectFactory; }
|
||||
|
||||
class MObject;
|
||||
class ExplicitPlacement;
|
||||
|
||||
using std::tr1::shared_ptr;
|
||||
using lib::HashIndexed;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A refcounting Handle to an MObject of type MO,
|
||||
* used to constrain or explicitly specify the
|
||||
* location where the MObject is supposed to
|
||||
* be within the Session/EDL
|
||||
* used to constrain or explicitly specify the location
|
||||
* where the MObject is supposed to be within the Session/EDL.
|
||||
* Placements are copyable (like values), but may be distinguished
|
||||
* by their identity (reference semantics), which is based on an
|
||||
* \link lib::HashIndexed hash-ID \endlink.
|
||||
*
|
||||
* Placements are defined to form a hierarchy, thereby mirroring
|
||||
* the relations between their referents to some degree. This allows
|
||||
* for building APIs targeted at specific kinds of MObjects, and
|
||||
* at the same time allows a specific placement to stand-in when
|
||||
* just a unspecific Placement<MObject> is required.
|
||||
*
|
||||
* @param MO the (compile time) type of the referent
|
||||
* @param B immediate base class of this placement
|
||||
*/
|
||||
template<class MO>
|
||||
class Placement : protected shared_ptr<MO>
|
||||
template<class MO, class B =MObject>
|
||||
class Placement ;
|
||||
|
||||
|
||||
/**
|
||||
* this specialisation forms the root of all placements
|
||||
* and defines all of Placement's actual functionality.
|
||||
*/
|
||||
template<>
|
||||
class Placement<MObject,MObject>
|
||||
: protected shared_ptr<MObject>,
|
||||
public HashIndexed<Placement<MObject>, lib::hash::LuidH> //////TODO: really need to be inherited publicly?
|
||||
{
|
||||
protected:
|
||||
typedef shared_ptr<MO> Base;
|
||||
typedef shared_ptr<MObject> _SmartPtr;
|
||||
typedef void (*Deleter)(MObject*);
|
||||
typedef lumiera::Time Time;
|
||||
typedef asset::shared_ptr<asset::Pipe> Pipe;
|
||||
typedef asset::shared_ptr<asset::Pipe> Pipe; ////TODO: get rid of this
|
||||
|
||||
|
||||
|
||||
|
|
@ -95,15 +132,15 @@ namespace mobject {
|
|||
* which is subject to placement.
|
||||
* @note we don't provide operator*
|
||||
*/
|
||||
virtual MO *
|
||||
virtual MObject *
|
||||
operator-> () const
|
||||
{
|
||||
ENSURE (*this);
|
||||
return Base::operator-> ();
|
||||
return _SmartPtr::operator-> ();
|
||||
}
|
||||
|
||||
operator string() const ;
|
||||
size_t use_count() const { return Base::use_count(); }
|
||||
size_t use_count() const { return _SmartPtr::use_count(); }
|
||||
|
||||
virtual ~Placement() {};
|
||||
|
||||
|
|
@ -123,44 +160,55 @@ namespace mobject {
|
|||
|
||||
|
||||
protected:
|
||||
Placement (MO & subject, void (*moKiller)(MO*))
|
||||
: shared_ptr<MO> (&subject, moKiller) {};
|
||||
Placement (MObject & subject, Deleter killer)
|
||||
: _SmartPtr (&subject, killer) {};
|
||||
|
||||
friend class session::MObjectFactory;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* === defining specialisations to be subclasses === */
|
||||
|
||||
#define DEFINE_SPECIALIZED_PLACEMENT(SUBCLASS, BASE) \
|
||||
template<> \
|
||||
class Placement<SUBCLASS> : public Placement<BASE> \
|
||||
{ \
|
||||
protected: \
|
||||
Placement (SUBCLASS & m, void (*moKiller)(MObject*)) \
|
||||
: Placement<BASE>::Placement (m, moKiller) \
|
||||
{ }; \
|
||||
friend class session::MObjectFactory; \
|
||||
\
|
||||
public: \
|
||||
virtual SUBCLASS* \
|
||||
operator-> () const \
|
||||
{ \
|
||||
ENSURE (INSTANCEOF (SUBCLASS, this->get())); \
|
||||
return static_cast<SUBCLASS*> \
|
||||
(shared_ptr<MObject>::operator-> ()); \
|
||||
} \
|
||||
/**
|
||||
* any specific placements are supposed to be derived
|
||||
* from Placement<MObject>, or an intermediary interface,
|
||||
* in case the second template parameter is used.
|
||||
* @note please refrain from adding additional functionality
|
||||
* to these subclasses. Especially, don't add any fields
|
||||
* to the subclass, as Placements are treated like values
|
||||
* at times, and thus slicing will happen, which in this
|
||||
* special case is acceptable.
|
||||
*/
|
||||
template<class MO, class B>
|
||||
class Placement
|
||||
: public Placement<B>
|
||||
{
|
||||
protected:
|
||||
typedef Placement<B> _Parent;
|
||||
typedef typename _Parent::Deleter Deleter;
|
||||
typedef typename _Parent::_SmartPtr _SmartPtr;
|
||||
|
||||
|
||||
Placement (MO & mo, Deleter killer)
|
||||
: _Parent (mo, killer)
|
||||
{ };
|
||||
friend class session::MObjectFactory;
|
||||
|
||||
public:
|
||||
virtual MO*
|
||||
operator-> () const
|
||||
{
|
||||
ENSURE (INSTANCEOF (MO, this->get()));
|
||||
return static_cast<MO*>
|
||||
(_SmartPtr::operator-> ());
|
||||
}
|
||||
};
|
||||
|
||||
/* a note to the maintainer: please don't add any fields or methods to
|
||||
* these subclasses which aren't also present in Placement<MObject>!
|
||||
* Placements are frequently treated like values and thus slicing
|
||||
* will happen, which in this special case is acceptable.
|
||||
*/
|
||||
|
||||
string
|
||||
format_PlacementID (Placement<MObject> const&) ;
|
||||
|
||||
|
||||
/** @todo cleanup uses of ref-to-placement. See Trac #115 */
|
||||
typedef Placement<MObject> PMO;
|
||||
|
||||
|
||||
} // namespace mobject
|
||||
|
|
|
|||
|
|
@ -33,10 +33,9 @@ namespace asset
|
|||
class Clip;
|
||||
}
|
||||
|
||||
namespace mobject
|
||||
{
|
||||
namespace session
|
||||
{
|
||||
namespace mobject {
|
||||
namespace session {
|
||||
|
||||
using asset::Media;
|
||||
typedef P<Media> PMedia;
|
||||
typedef P<asset::Clip> PClipAsset;
|
||||
|
|
@ -57,7 +56,7 @@ namespace mobject
|
|||
class Clip : public AbstractMO
|
||||
{
|
||||
protected:
|
||||
/** startpos in source */
|
||||
/** start position in source */
|
||||
Time start_;
|
||||
|
||||
/** @todo using a mere ref here is against the scheme and only
|
||||
|
|
@ -93,14 +92,8 @@ namespace mobject
|
|||
};
|
||||
|
||||
typedef Placement<Clip> PClipMO;
|
||||
|
||||
|
||||
|
||||
} // namespace mobject::session
|
||||
|
||||
/** Placement<Clip> defined to be subclass of Placement<MObject> */
|
||||
DEFINE_SPECIALIZED_PLACEMENT (session::Clip, MObject);
|
||||
|
||||
|
||||
} // namespace mobject
|
||||
|
||||
|
||||
}} // namespace mobject::session
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,26 +32,19 @@
|
|||
using std::string;
|
||||
|
||||
|
||||
namespace mobject
|
||||
{
|
||||
namespace session
|
||||
namespace mobject {
|
||||
namespace session {
|
||||
|
||||
|
||||
class Effect : public AbstractMO
|
||||
{
|
||||
|
||||
|
||||
class Effect : public AbstractMO
|
||||
{
|
||||
protected:
|
||||
/** Identifier of the Plugin to be used */
|
||||
string plugID;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace mobject::session
|
||||
|
||||
/** Placement<Effect> defined to be subclass of Placement<MObject> */
|
||||
DEFINE_SPECIALIZED_PLACEMENT (session::Effect, MObject);
|
||||
|
||||
} // namespace mobject
|
||||
protected:
|
||||
/** Identifier of the Plugin to be used */
|
||||
string plugID;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}} // namespace mobject::session
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ namespace mobject
|
|||
|
||||
|
||||
RelativeLocation&
|
||||
LocatingPin::operator() (PMO refObj, Time offset)
|
||||
LocatingPin::operator() (PlacementRef& refObj, Time offset)
|
||||
{
|
||||
return static_cast<RelativeLocation&>
|
||||
(addChain (new RelativeLocation (refObj, offset)));
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@
|
|||
** RelativeLocation#resolve(LocatingSolution&) etc. If this is to be extended,
|
||||
** we'll need a real spatial discrete constraint solver (and this probably will be
|
||||
** some library implementation, because the problem is anything but trivial).
|
||||
**
|
||||
** @todo this can be considered a preliminary sketch without being backed
|
||||
** by actual functionality. Just enough to be able to drive the design of
|
||||
** other parts ahead. See esp. Trac #100, which contains an idea for a
|
||||
** refactoring.
|
||||
**
|
||||
*/
|
||||
|
||||
|
|
@ -53,21 +58,28 @@ using boost::scoped_ptr;
|
|||
|
||||
namespace asset { class Pipe; }
|
||||
|
||||
namespace mobject
|
||||
{
|
||||
namespace mobject {
|
||||
|
||||
class MObject;
|
||||
template<class MO> class Placement;
|
||||
typedef Placement<MObject> PMO;
|
||||
|
||||
namespace session
|
||||
{
|
||||
///////////////////////////////////////////TODO: all those dependencies are just a plain mess right now.
|
||||
//
|
||||
//template<class MO, class B=MObject>
|
||||
//class Placement ;
|
||||
//typedef Placement<MObject> PMO;
|
||||
|
||||
class PlacementRef; ///TODO: as of 5/09 the idea is to phase out direct dependency on the placement class and recast those dependencies in terms of PlacementRef
|
||||
|
||||
|
||||
namespace session {
|
||||
|
||||
class FixedLocation;
|
||||
class RelativeLocation;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Positioning specification, possibliy chained
|
||||
* Positioning specification, possibly chained
|
||||
* to further specifications. The base class LocatingPin
|
||||
* is a "no-op" specification which doesn't constrain the
|
||||
* possible locations and thus can be embedded into pristine
|
||||
|
|
@ -84,7 +96,7 @@ namespace mobject
|
|||
typedef lumiera::Time Time;
|
||||
typedef Time* Track; //TODO dummy declaration; we don't use Tracks as first-class entity any longer
|
||||
typedef std::tr1::shared_ptr<asset::Pipe> Pipe;
|
||||
typedef std::pair<Time,Pipe> SolutionData; //TODO (ichthyo consideres better passing of solution by subclass)
|
||||
typedef std::pair<Time,Pipe> SolutionData; //TODO (ichthyo considers better passing of solution by subclass)
|
||||
struct LocatingSolution;
|
||||
|
||||
/** next additional Pin, if any */
|
||||
|
|
@ -104,7 +116,7 @@ namespace mobject
|
|||
/* Factory functions for adding LocatingPins */
|
||||
|
||||
FixedLocation& operator() (Time start, Track track=0);
|
||||
RelativeLocation& operator() (PMO refObj, Time offset=0);
|
||||
RelativeLocation& operator() (PlacementRef& refObj, Time offset=0);
|
||||
|
||||
LocatingPin (const LocatingPin&);
|
||||
LocatingPin& operator= (const LocatingPin&);
|
||||
|
|
@ -117,7 +129,7 @@ namespace mobject
|
|||
//TODO (for working out the buildable interface; ctor should be protected)
|
||||
protected:
|
||||
|
||||
friend class Placement<MObject>;
|
||||
// friend class Placement<MObject>;
|
||||
|
||||
/**
|
||||
* @internal helper for the (preliminary)
|
||||
|
|
@ -125,7 +137,7 @@ protected:
|
|||
* @todo we can't sensibly reason about tracks,
|
||||
* because at the moment (10/07) we lack a track implementation...
|
||||
* @todo shouldn't we use a range-restriction LocatingPin (subclass)
|
||||
* to represent the to-be-found solution? (ichthyo: siehe Trac #100)
|
||||
* to represent the to-be-found solution? (ichthyo: see Trac #100)
|
||||
*/
|
||||
struct LocatingSolution
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,29 +28,22 @@
|
|||
|
||||
|
||||
|
||||
namespace mobject
|
||||
{
|
||||
namespace session
|
||||
namespace mobject {
|
||||
namespace session {
|
||||
|
||||
|
||||
/**
|
||||
* Meta-MObject doesn't represent real Media Content,
|
||||
* but rather all sorts of Processing Instructions
|
||||
* and other metadata, which can be placed and
|
||||
* attached within the EDL/Session.
|
||||
*/
|
||||
class Meta : public AbstractMO
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Meta-MObject doesn't represent real Media Content,
|
||||
* but rather all sorts of Processing Instructions
|
||||
* and other metadata, which can be placed and
|
||||
* attached within the EDL/Session.
|
||||
*/
|
||||
class Meta : public AbstractMO
|
||||
{
|
||||
///////////
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace mobject::session
|
||||
///////////
|
||||
};
|
||||
|
||||
/** Placement<Meta> defined to be subclass of Placement<MObject> */
|
||||
DEFINE_SPECIALIZED_PLACEMENT (session::Meta, MObject);
|
||||
|
||||
} // namespace mobject
|
||||
|
||||
|
||||
}} // namespace mobject::session
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#ifndef MOBJECT_SESSION_RELATIVELOCATION_H
|
||||
#define MOBJECT_SESSION_RELATIVELOCATION_H
|
||||
|
||||
#include "proc/mobject/placement-ref.hpp"
|
||||
#include "proc/mobject/session/locatingpin.hpp"
|
||||
|
||||
|
||||
|
|
@ -35,10 +36,16 @@ namespace mobject
|
|||
{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @todo just a design sketch, nothing finished yet.
|
||||
* possibly to be reworked or phased out completely.
|
||||
* See Trac #100
|
||||
*/
|
||||
class RelativeLocation : public LocatingPin
|
||||
{
|
||||
const PMO & anchor_; ////////////TODO: ooooops, this is a nasty design problem!!!
|
||||
// const PMO & anchor_; ////////////TODO: ooooops, this is a nasty design problem!!!
|
||||
|
||||
const PlacementRef anchor_;
|
||||
|
||||
public:
|
||||
|
||||
|
|
@ -51,7 +58,7 @@ namespace mobject
|
|||
};
|
||||
|
||||
protected:
|
||||
RelativeLocation (const PMO& a, Time ofs) : anchor_(a), offset_(ofs) { }
|
||||
RelativeLocation (PlacementRef const& a, Time ofs) : anchor_(a), offset_(ofs) { }
|
||||
friend class LocatingPin;
|
||||
|
||||
/** the kind of relation denoted by this Placement */
|
||||
|
|
|
|||
|
|
@ -30,10 +30,9 @@
|
|||
|
||||
namespace asset { class Track; }
|
||||
|
||||
namespace mobject
|
||||
{
|
||||
namespace session
|
||||
{
|
||||
namespace mobject {
|
||||
namespace session {
|
||||
|
||||
using lumiera::P;
|
||||
|
||||
class Track;
|
||||
|
|
@ -41,26 +40,26 @@ namespace mobject
|
|||
|
||||
typedef P<Track> PTrack;
|
||||
typedef P<TrackAsset> PTrackAsset;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A Track is grouping device within the EDL.
|
||||
* The corresponding Placement by which this Track object is refered
|
||||
* The corresponding Placement by which this Track object is referred
|
||||
* defines fallback placing properties to be used by all objects placed on this track
|
||||
* in case they don't specify more concrete placements.
|
||||
* Typically, tracks are used do make default processing pipe connections,
|
||||
* define a layer or pan for sound and for for disabling groups
|
||||
* of clips. Note tracks are grouped in a tree like fashion.
|
||||
* \par
|
||||
* This Media Object (often refered to as "track-MO") is allways dealt with
|
||||
* This Media Object (often referred to as "track-MO") is always dealt with
|
||||
* locally within one EDL. Client code normally doesn't have to care for creating
|
||||
* or retrieving track-MO. Rather, it referes to the global track-asset-ID. The same
|
||||
* or retrieving track-MO. Rather, it refers to the global track-asset-ID. The same
|
||||
* holds true when placing some other Media Object onto a track: the corresponding
|
||||
* placement just refers the global trackID, while the builder automatically retrieves
|
||||
* the matching track-MO for the EDL in question. If some EDL contains several instances
|
||||
* (track-MO) refering to the same trackID (asset), then this causes all objects placed
|
||||
* (track-MO) referring to the same trackID (asset), then this causes all objects placed
|
||||
* onto this track to be included several times in the resulting render nodes network
|
||||
* (possibliy with varying placement properties)
|
||||
* (possibly with varying placement properties)
|
||||
*/
|
||||
class Track : public Meta
|
||||
{
|
||||
|
|
@ -70,7 +69,7 @@ namespace mobject
|
|||
protected:
|
||||
Track (PTrackAsset&);
|
||||
friend class MObjectFactory;
|
||||
|
||||
|
||||
public:
|
||||
/** Child tracks in a tree structure */
|
||||
vector<Placement<Track> > subTracks; ////TODO: it should really work with Placements! this here is just a decoy!!!!!!!
|
||||
|
|
@ -82,8 +81,8 @@ namespace mobject
|
|||
|
||||
} // namespace mobject::session
|
||||
|
||||
/** Placement<Track> defined to be subclass of Placement<MObject> */
|
||||
DEFINE_SPECIALIZED_PLACEMENT (session::Track, session::Meta);
|
||||
|
||||
/** Placement<Track> defined to be subclass of Placement<Meta> */
|
||||
template class Placement<session::Track, session::Meta>;
|
||||
|
||||
} // namespace mobject
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue