add stubs to make it link, add some typelist utils
This commit is contained in:
parent
c3b1048fc4
commit
000538f6ef
9 changed files with 379 additions and 18 deletions
146
src/common/typelistutil.hpp
Normal file
146
src/common/typelistutil.hpp
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
TYPELISTUTIL.hpp - metaprogramming utilities for lists-of-types
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2007, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
====================================================================
|
||||
This code is heavily inspired by
|
||||
The Loki Library (loki-lib/trunk/include/loki/Sequence.h)
|
||||
Copyright (c) 2001 by Andrei Alexandrescu
|
||||
Copyright (c) 2005 by Peter Kümmel
|
||||
This Loki code accompanies the book:
|
||||
Alexandrescu, Andrei. "Modern C++ Design: Generic Programming
|
||||
and Design Patterns Applied".
|
||||
Copyright (c) 2001. Addison-Wesley. ISBN 0201704315
|
||||
|
||||
Loki Copyright Notice:
|
||||
Permission to use, copy, modify, distribute and sell this software for any
|
||||
purpose is hereby granted without fee, provided that the above copyright
|
||||
notice appear in all copies and that both that copyright notice and this
|
||||
permission notice appear in supporting documentation.
|
||||
The author makes no representations about the suitability of this software
|
||||
for any purpose. It is provided "as is" without express or implied warranty.
|
||||
*/
|
||||
|
||||
|
||||
/** @file typelistutil.hpp
|
||||
** Helpers for working with cinelerra::typelist::Types (i.e. lists-of-types).
|
||||
**
|
||||
** @see cinelerra::query::ConfigRules usage example
|
||||
** @see typelist.hpp
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CINELERRA_TYPELISTUTIL_H
|
||||
#define CINELERRA_TYPELISTUTIL_H
|
||||
|
||||
#include "common/typelist.hpp"
|
||||
|
||||
|
||||
|
||||
namespace cinelerra
|
||||
{
|
||||
namespace typelist
|
||||
{
|
||||
|
||||
/**
|
||||
* Apply a template to a collection of types.
|
||||
* The resulting class ends up inheriting from an instantiation
|
||||
* of the templace for each of the types in the list.
|
||||
*/
|
||||
template
|
||||
< class TYPES // List of Types
|
||||
, template<class> class _X_ // your-template-goes-here
|
||||
, class BASE = NullType // Base class at end of chain
|
||||
>
|
||||
class InstantiateForEach;
|
||||
|
||||
|
||||
template<template<class> class _X_, class BASE>
|
||||
class InstantiateForEach<NullType, _X_, BASE>
|
||||
: public BASE
|
||||
{
|
||||
public:
|
||||
typedef BASE Unit;
|
||||
typedef NullType Next;
|
||||
};
|
||||
|
||||
|
||||
template
|
||||
< class TY, typename TYPES
|
||||
, template<class> class _X_
|
||||
, class BASE
|
||||
>
|
||||
class InstantiateForEach<Node<TY, TYPES>, _X_, BASE>
|
||||
: public _X_<TY>,
|
||||
public InstantiateForEach<TYPES, _X_, BASE>
|
||||
{
|
||||
public:
|
||||
typedef _X_<TY> Unit;
|
||||
typedef InstantiateForEach<TYPES,_X_> Next;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Build a single inheritance chain of template instantiations.
|
||||
* Needs the help of the user provided Template, which now has
|
||||
* to take a second parameter and use this as Base class.
|
||||
* The resulting class ends up (single) inheriting from an
|
||||
* instantiation of the templace for each of the types, while
|
||||
* overrideing/implementing the provided base class.
|
||||
*/
|
||||
template
|
||||
< class TYPES // List of Types
|
||||
, template<class,class> class _X_ // your-template-goes-here
|
||||
, class BASE = NullType // Base class at end of chain
|
||||
>
|
||||
class InstantiateChained;
|
||||
|
||||
|
||||
template<template<class,class> class _X_, class BASE>
|
||||
class InstantiateChained<NullType, _X_, BASE>
|
||||
: public BASE
|
||||
{
|
||||
public:
|
||||
typedef BASE Unit;
|
||||
typedef NullType Next;
|
||||
};
|
||||
|
||||
|
||||
template
|
||||
< class TY, typename TYPES
|
||||
, template<class,class> class _X_
|
||||
, class BASE
|
||||
>
|
||||
class InstantiateChained<Node<TY, TYPES>, _X_, BASE>
|
||||
: public _X_< TY
|
||||
, InstantiateChained<TYPES, _X_, BASE>
|
||||
>
|
||||
{
|
||||
public:
|
||||
typedef InstantiateChained<TYPES,_X_> Next;
|
||||
typedef _X_<TY,Next> Unit;
|
||||
};
|
||||
|
||||
|
||||
} // namespace typelist
|
||||
|
||||
} // namespace cinelerra
|
||||
#endif
|
||||
|
|
@ -291,8 +291,19 @@ namespace asset
|
|||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** promote subtype-ptr to PAsset, e.g. for comparing */
|
||||
template<class A>
|
||||
inline const PcAsset
|
||||
pAsset (const shared_ptr<A>& subPtr)
|
||||
{
|
||||
return static_pointer_cast<const Asset,A> (subPtr);
|
||||
}
|
||||
|
||||
/** ordering of Asset smart ptrs based on Ident tuple.
|
||||
* @todo currently supporting only smart_ptr<Asset>. */
|
||||
* @todo currently supporting only smart_ptr<Asset>.
|
||||
* @todo should better be done using boost::operator */
|
||||
inline bool operator== (const PcAsset& a1, const PcAsset& a2) { return a1 && a2 && ( 0==a1->ident.compare(a2->ident));}
|
||||
inline bool operator< (const PcAsset& a1, const PcAsset& a2) { return a1 && a2 && (-1==a1->ident.compare(a2->ident));}
|
||||
inline bool operator> (const PcAsset& a1, const PcAsset& a2) { return a2 < a1; }
|
||||
|
|
@ -300,6 +311,13 @@ namespace asset
|
|||
inline bool operator<= (const PcAsset& a1, const PcAsset& a2) { return !(a1 > a2); }
|
||||
inline bool operator!= (const PcAsset& a1, const PcAsset& a2) { return !(a1== a2); }
|
||||
|
||||
inline bool operator== (const PAsset& a1, const PAsset& a2) { return pAsset(a1) == pAsset(a2); }
|
||||
inline bool operator< (const PAsset& a1, const PAsset& a2) { return pAsset(a1) < pAsset(a2); }
|
||||
inline bool operator> (const PAsset& a1, const PAsset& a2) { return pAsset(a1) > pAsset(a2); }
|
||||
inline bool operator>= (const PAsset& a1, const PAsset& a2) { return pAsset(a1) >= pAsset(a2); }
|
||||
inline bool operator<= (const PAsset& a1, const PAsset& a2) { return pAsset(a1) <= pAsset(a2); }
|
||||
inline bool operator!= (const PAsset& a1, const PAsset& a2) { return pAsset(a1) != pAsset(a2); }
|
||||
|
||||
/** ordering of Asset Ident tuples.
|
||||
* @note version is irrelevant */
|
||||
inline int
|
||||
|
|
@ -311,14 +329,6 @@ namespace asset
|
|||
return name.compare (oi.name);
|
||||
}
|
||||
|
||||
/** promote to PAsset, e.g. for comparing */
|
||||
template<class A>
|
||||
inline PcAsset
|
||||
pAsset (shared_ptr<A>& subPtr)
|
||||
{
|
||||
return static_pointer_cast<const Asset,A> (subPtr);
|
||||
}
|
||||
|
||||
|
||||
/** convienient for debugging */
|
||||
inline string str (const PcAsset& a)
|
||||
|
|
|
|||
|
|
@ -54,6 +54,12 @@ namespace asset
|
|||
|
||||
|
||||
|
||||
PPort
|
||||
Port::query (string properties)
|
||||
{
|
||||
return Struct::create (Query<Port> (properties));
|
||||
}
|
||||
|
||||
void
|
||||
Port::switchProcPatt (PProcPatt& another)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ namespace asset
|
|||
void switchProcPatt (PProcPatt& another);
|
||||
|
||||
/** convienience shortcut for retrieving default configured ports */
|
||||
static PPort query (string properties) { return Struct::create (Query<Port> (properties)); }
|
||||
static PPort query (string properties) ;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "proc/asset/struct.hpp"
|
||||
#include "proc/asset/procpatt.hpp"
|
||||
#include "proc/asset/track.hpp"
|
||||
#include "proc/asset/port.hpp"
|
||||
#include "proc/mobject/session.hpp"
|
||||
|
||||
#include "common/query.hpp"
|
||||
|
|
@ -37,6 +38,9 @@ using cinelerra::query::normalizeID;
|
|||
namespace asset
|
||||
{
|
||||
|
||||
/****** NOTE: not implemented yet. What follows is a hack to build simple tests *******/
|
||||
|
||||
|
||||
namespace // common Struct Asset implementation details
|
||||
{
|
||||
/** @internal derive a sensible asset ident tuple when creating
|
||||
|
|
@ -51,6 +55,16 @@ namespace asset
|
|||
Category category (STRUCT,"tracks");
|
||||
return Asset::Ident (name, category );
|
||||
}
|
||||
|
||||
typedef std::pair<string,string> PortIDs;
|
||||
|
||||
PortIDs
|
||||
createPortIdent (const Query<Port>& query)
|
||||
{
|
||||
string name ("port-" + query); // TODO get some more sensible dummy values
|
||||
TODO ("port naming scheme??");
|
||||
return PortIDs (name, "mpeg"); // dummy stream type
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -74,6 +88,19 @@ namespace asset
|
|||
}
|
||||
|
||||
|
||||
/** Similar instance for Port Query....
|
||||
* @todo better a generic implementation utilizing ConfigQuery....
|
||||
*/
|
||||
template<>
|
||||
shared_ptr<Port>
|
||||
StructFactory::operator() (const Query<Port>& query)
|
||||
{
|
||||
TODO ("actually evaluate the query...");
|
||||
PortIDs ids (createPortIdent (query));
|
||||
return operator() (ids.first, ids.second);
|
||||
}
|
||||
|
||||
|
||||
/** Factory method for creating Ports explicitly.
|
||||
* Normalizes port- and streamID, then retrieves the
|
||||
* default processing pattern (ProcPatt) for this streamID.
|
||||
|
|
|
|||
|
|
@ -22,10 +22,12 @@
|
|||
|
||||
|
||||
#include "proc/mobject/session/defsmanager.hpp"
|
||||
#include "proc/asset/procpatt.hpp"
|
||||
#include "proc/asset/port.hpp"
|
||||
|
||||
using asset::Query;
|
||||
using asset::Port;
|
||||
using asset::ProcPatt;
|
||||
|
||||
namespace mobject
|
||||
{
|
||||
|
|
@ -40,13 +42,22 @@ namespace mobject
|
|||
|
||||
|
||||
/** create or retrieve a default-configured port asset.
|
||||
* @param
|
||||
*/
|
||||
template<>
|
||||
shared_ptr<Port>
|
||||
DefsManager::operator() (const Query<Port>& properties)
|
||||
DefsManager::operator() (const Query<Port>& capabilities)
|
||||
{
|
||||
|
||||
UNIMPLEMENTED ("query for default port with capabilities");
|
||||
}
|
||||
|
||||
|
||||
/** create or retrieve a default-configured processing pattern.
|
||||
*/
|
||||
template<>
|
||||
shared_ptr<ProcPatt>
|
||||
DefsManager::operator() (const Query<ProcPatt>& capabilities)
|
||||
{
|
||||
UNIMPLEMENTED ("query for default processing pattern with capabilities");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -189,6 +189,27 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
TEST "TypeListUtil_test" TypeListUtil_test <<END
|
||||
out: ctor DoIt<Block<13> >
|
||||
out: ctor DoIt<Block< 8> >
|
||||
out: ctor DoIt<Block< 5> >
|
||||
out: ctor DoIt<Block< 3> >
|
||||
out: ctor DoIt<Block< 2> >
|
||||
out: ctor DoIt<Block< 1> >
|
||||
out: Block< 2>::eat(..)
|
||||
out: Block< 5>::eat(..)
|
||||
out: Block<13>::eat(..)
|
||||
out: gulp!
|
||||
out: dtor DoIt<Block< 1> >
|
||||
out: dtor DoIt<Block< 2> >
|
||||
out: dtor DoIt<Block< 3> >
|
||||
out: dtor DoIt<Block< 5> >
|
||||
out: dtor DoIt<Block< 8> >
|
||||
out: dtor DoIt<Block<13> >
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "VisitingTool_test" VisitingTool_test <<END
|
||||
out: === Babbler meets Boss and BigBoss ===
|
||||
out: Hello Boss, nice to meet you...
|
||||
|
|
|
|||
140
tests/components/common/typelistutiltest.cpp
Normal file
140
tests/components/common/typelistutiltest.cpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
TypeListUtil(Test) - check the typelist helpers
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2007, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "common/test/run.hpp"
|
||||
#include "common/typelistutil.hpp"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
|
||||
using std::string;
|
||||
using std::cout;
|
||||
|
||||
|
||||
namespace cinelerra
|
||||
{
|
||||
namespace typelist
|
||||
{
|
||||
namespace test
|
||||
{
|
||||
|
||||
/** template for generating lots of different test types */
|
||||
template<int I>
|
||||
struct Block
|
||||
{
|
||||
static string name;
|
||||
string talk() { return name+"::eat(..)"; }
|
||||
};
|
||||
|
||||
|
||||
boost::format fmt ("Block<%2i>");
|
||||
|
||||
template<int I>
|
||||
string Block<I>::name = str (fmt % I);
|
||||
|
||||
|
||||
|
||||
/** Use this building block for assembling an abstract interface */
|
||||
template<class X>
|
||||
class TakeIt
|
||||
{
|
||||
public:
|
||||
virtual void eat (X& x) = 0;
|
||||
virtual ~TakeIt() { }
|
||||
};
|
||||
|
||||
/** Use this building block for chaining corresponding implementation classes. */
|
||||
template<class X, class BASE>
|
||||
class DoIt
|
||||
: public BASE
|
||||
{
|
||||
protected:
|
||||
DoIt () { cout << "ctor DoIt<"<< X::name << " >\n";}
|
||||
virtual ~DoIt() { cout << "dtor DoIt<"<< X::name << " >\n";}
|
||||
public:
|
||||
void eat (X& x) { cout << x.talk() << "\n";}
|
||||
using BASE::eat; // prevent shaddowing
|
||||
};
|
||||
|
||||
typedef Types< Block<1>
|
||||
, Block<2>
|
||||
, Block<3>
|
||||
, Block<5>
|
||||
, Block<8>
|
||||
, Block<13>
|
||||
>::List TheTypes;
|
||||
|
||||
typedef InstantiateForEach<TheTypes,TakeIt> TheInterface;
|
||||
|
||||
|
||||
struct BaseImpl : public TheInterface
|
||||
{
|
||||
void eat() { cout << "gulp!\n"; }
|
||||
};
|
||||
|
||||
typedef InstantiateChained<TheTypes,DoIt, BaseImpl> NumberBabbler;
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* @test check the helpers for dealing with lists-of-types.
|
||||
* <ul><li>build an interface and an implementation class
|
||||
* by inheriting template instantiations
|
||||
* for a collection of classes</li>
|
||||
* </ul>
|
||||
*/
|
||||
class TypeListUtil_test : public Test
|
||||
{
|
||||
virtual void run(Arg arg)
|
||||
{
|
||||
NumberBabbler me_can_has_more_numberz;
|
||||
|
||||
ASSERT (INSTANCEOF (TheInterface, &me_can_has_more_numberz));
|
||||
|
||||
TheTypes::Tail::Head b2; // Block<2>
|
||||
TheTypes::Tail::Tail::Tail::Head b5; // Block<5>
|
||||
TheTypes::Tail::Tail::Tail::Tail::Tail::Head b13; // Block<13>
|
||||
|
||||
me_can_has_more_numberz.eat (b2);
|
||||
me_can_has_more_numberz.eat (b5);
|
||||
|
||||
TakeIt<Block<13> >& subInterface = me_can_has_more_numberz;
|
||||
|
||||
subInterface.eat (b13);
|
||||
me_can_has_more_numberz.eat();
|
||||
|
||||
INFO (test, "SizeOf = %i", sizeof(me_can_has_more_numberz));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (TypeListUtil_test, "unit common");
|
||||
|
||||
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace typelist
|
||||
|
||||
} // namespace cinelerra
|
||||
|
|
@ -2450,26 +2450,26 @@ Like all [[structural assets|StructAsset]], ~ProcPatt employs a special naming s
|
|||
<pre>a given Render Engine configuration is a list of Processors. Each Processor in turn contains a Graph of ProcNode.s to do the acutal data processing. In order to cary out any calculations, the Processor needs to be called with a StateProxy containing the state information for this RenderProcess
|
||||
</pre>
|
||||
</div>
|
||||
<div title="QueryImplProlog" modifier="Ichthyostega" modified="200801210153" created="200801202321" tags="draft design" changecount="11">
|
||||
<div title="QueryImplProlog" modifier="Ichthyostega" modified="200801270339" created="200801202321" tags="draft design" changecount="14">
|
||||
<pre>//obviously, getting this one to work requires quite a lot of technical details to be planned and implemented.// This said...
|
||||
The intention is to get much more readable ("declarative") and changeable configuration as by programming it directly within the implementation of some object.
|
||||
|
||||
!Draft
|
||||
As an example, specifying how a Track can be configured for connecting automatically to some "mpeg" bus (=port)
|
||||
{{{
|
||||
retrieve(O, Cap) :- find(T), capabilities(Cap).
|
||||
retrieve(O, Cap) :- make(T), capabilities(Cap).
|
||||
retrieve(O, Cap) :- find(O), capabilities(Cap).
|
||||
retrieve(O, Cap) :- make(O), capabilities(Cap).
|
||||
capabilities(Q) :- call(Q).
|
||||
|
||||
stream(T, mpeg) :- type(T, track), type(P, port), retrieve(P, stream(P,mpeg)), place_to(P, T).
|
||||
}}}
|
||||
|
||||
Then, running the goal {{{:-retrieve(T, stream(T,mpeg)).}}} would search a Track object, try to retrieve a port object with stream-type=mpeg and associate the track with this Port. This relies on a predicate "stream(P,mpeg)" implemented (natively) for the port object. So, "Cap" is the query issued from calling code &mdash; here {{{stream(T,mpeg)}}}, the type guard {{{type(T, track)}}} will probably be handled or inserted inserted automatically, while the predicate implementations for find/1, make/1, stream/2, and place_to/2 are to be provided by the target types.
|
||||
Then, running the goal {{{:-retrieve(T, stream(T,mpeg)).}}} would search a Track object, try to retrieve a port object with stream-type=mpeg and associate the track with this Port. This relies on a predicate "stream(P,mpeg)" implemented (natively) for the port object. So, "Cap" is the query issued from calling code &mdash; here {{{stream(T,mpeg)}}}, the type guard {{{type(T, track)}}} will probably be handled or inserted automatically, while the predicate implementations for find/1, make/1, stream/2, and place_to/2 are to be provided by the target types.
|
||||
* __The supporting system__ had to combine several code snippets into one rule system to be used for running queries, with some global base rules, rules injected by each individual participating object kind and finally user provided rules added by the current session. The actual query is bound to "Cap" (and consequently run as a goal by {{{call(Q)}}}). The implementation needs to provide a symbol table associating variable terms (like "T" or "P") to C/C++ object types, enabling the participating object kinds to register their specific predicate implementations. This is crucial, because there can be no general scheme of object-provided predicates (for each object kind different predicates make sense, e.g. [[ports|PortHandling]] have other possibilities than [[wiring requests|WiringRequest]]). Basically, a query issues a Prolog goal, which in turn evaluates domain specific predicates provided by the participating objects and thus calls back into C/C++ code. The supporting system maintains the internal connection (via the "type" predicate) such that from Prolog viewpoint it looks as if we were binding Variables directly to object instances. (there are some nasty technical details because of the backtracking nature of Prolog evaluations which need to be hidden away)
|
||||
* Any __participating object kind__ needs a way to declare domain specific predicates, thus triggering the registration of the necessary hooks within the supporting system. Moreover, it should be able to inject further prolog code (as shown in the example above with the {{{strem(T, mpeg)}}} predicate. For each of these new domain specific predicates, there needs to be a functor which can be invoked when the C implementation of the predicate is called from Prolog (in some cases even later, when the final solution is "executed", e.g. a new instance has been created and now some properties need to be set).
|
||||
|
||||
!!a note on Plugins
|
||||
In the design of the Cinelerra-3 Proc Layer done thus far, we provide //no possibility to introduce a new object kind// into the system via plugin interface. The system uses a fixed collection of classes intended to cover all needs (Clip, Effect, Track, Port, Label, Automation, ~Macro-Clips). Thus, plugins will only be able to provide new parametrisations of existing classes. This should not be any real limitation, because the whole system is designed to achieve most of its functionality by freely combining rather basic object kinds. As a plus, it plays nicely with any plain-C based plugin interface. For example, we will have C++ adapter classes for the most common sorts of effect plugin (pull system and synchronous frame-by-frame push with buffering) with a thin C adaptation layer for the specific external plugin systems used.
|
||||
In the design of the Cinelerra-3 Proc Layer done thus far, we provide //no possibility to introduce a new object kind// into the system via plugin interface. The system uses a fixed collection of classes intended to cover all needs (Clip, Effect, Track, Port, Label, Automation, ~Macro-Clips). Thus, plugins will only be able to provide new parametrisations of existing classes. This should not be any real limitation, because the whole system is designed to achieve most of its functionality by freely combining rather basic object kinds. As a plus, it plays nicely with any plain-C based plugin interface. For example, we will have C++ adapter classes for the most common sorts of effect plugin (pull system and synchronous frame-by-frame push with buffering) with a thin C adaptation layer for the specific external plugin systems used. Everything beyond this point can be considered "condiguration data" (including the actual plugin implementation to be loaded)
|
||||
</pre>
|
||||
</div>
|
||||
<div title="RSSReaderPlugin" modifier="Ichthyostega" created="200708081515" tags="systemConfig" changecount="1">
|
||||
|
|
|
|||
Loading…
Reference in a new issue