--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG 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 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG 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 CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Cambell Prince, cambell.prince@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory/safe_ptr.h>
+
+#include <boost/noncopyable.hpp>
+#include <boost/property_tree/ptree_fwd.hpp>
+#include <boost/thread/future.hpp>
+
+#include <functional>
+#include <string>
+#include <vector>
+
+namespace caspar { namespace core {
+
+class basic_frame;
+class parameters;
+struct video_format_desc;
+
+struct write_frame_consumer : boost::noncopyable
+{
+ virtual ~write_frame_consumer() {}
+
+ virtual void send(const safe_ptr<basic_frame>& frame) = 0;
+ virtual std::wstring print() const = 0;
+ //virtual boost::property_tree::wptree info() const = 0;
+};
+
+}}
\ No newline at end of file
<Lib />\r
</ItemDefinitionGroup>\r
<ItemGroup>\r
+ <ClInclude Include="consumer\write_frame_consumer.h" />\r
<ClInclude Include="mixer\audio\audio_util.h" />\r
<ClInclude Include="mixer\gpu\fence.h" />\r
<ClInclude Include="mixer\gpu\shader.h" />\r
<ClInclude Include="monitor\monitor.h" />\r
<ClInclude Include="producer\channel\channel_producer.h" />\r
<ClInclude Include="thumbnail_generator.h" />\r
+ <ClInclude Include="producer\layer\layer_producer.h" />\r
<ClInclude Include="video_channel.h" />\r
<ClInclude Include="consumer\output.h" />\r
<ClInclude Include="consumer\frame_consumer.h" />\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
<ClCompile Include="thumbnail_generator.cpp" />\r
- <ClCompile Include="video_channel.cpp" />\r
+ <ClCompile Include="producer\layer\layer_producer.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ </ClCompile>\r
+ <ClCompile Include="video_channel.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">StdAfx.h</PrecompiledHeaderFile>\r
+ </ClCompile>\r
<ClCompile Include="consumer\frame_consumer.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<Filter Include="source\monitor">\r
<UniqueIdentifier>{d8525088-072a-47d2-b6e1-ad662881f505}</UniqueIdentifier>\r
</Filter>\r
+ <Filter Include="source\producer\layer">\r
+ <UniqueIdentifier>{4e098e4c-7467-446f-990d-d4486d179edb}</UniqueIdentifier>\r
+ </Filter>\r
<Filter Include="source\parameters">\r
<UniqueIdentifier>{d04737a6-96b2-40cd-b1e7-e90b69006cd1}</UniqueIdentifier>\r
</Filter>\r
<ClInclude Include="producer\channel\channel_producer.h">\r
<Filter>source\producer\channel</Filter>\r
</ClInclude>\r
+ <ClInclude Include="producer\layer\layer_producer.h">\r
+ <Filter>source\producer\layer</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="consumer\write_frame_consumer.h">\r
+ <Filter>source\consumer</Filter>\r
+ </ClInclude>\r
<ClInclude Include="thumbnail_generator.h">\r
<Filter>source</Filter>\r
</ClInclude>\r
<ClCompile Include="thumbnail_generator.cpp">\r
<Filter>source</Filter>\r
</ClCompile>\r
+ <ClCompile Include="producer\layer\layer_producer.cpp">\r
+ <Filter>source\producer\layer</Filter>\r
+ </ClCompile>\r
<ClCompile Include="monitor\monitor.cpp">\r
<Filter>source\monitor</Filter>\r
</ClCompile>\r
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG 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 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG 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 CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Cambell Prince, cambell.prince@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "layer_producer.h"
+
+#include "../../consumer/write_frame_consumer.h"
+#include "../../consumer/output.h"
+#include "../../video_channel.h"
+
+#include "../stage.h"
+#include "../frame/basic_frame.h"
+#include "../frame/frame_factory.h"
+#include "../../mixer/write_frame.h"
+#include "../../mixer/read_frame.h"
+
+#include <common/exception/exceptions.h>
+#include <common/memory/memcpy.h>
+#include <common/concurrency/future_util.h>
+
+#include <boost/format.hpp>
+
+#include <tbb/concurrent_queue.h>
+
+namespace caspar { namespace core {
+
+class layer_consumer : public write_frame_consumer
+{
+ tbb::concurrent_bounded_queue<safe_ptr<basic_frame>> frame_buffer_;
+
+public:
+ layer_consumer()
+ {
+ frame_buffer_.set_capacity(2);
+ }
+
+ ~layer_consumer()
+ {
+ }
+
+ // write_frame_consumer
+
+ virtual void send(const safe_ptr<basic_frame>& src_frame) override
+ {
+ frame_buffer_.try_push(src_frame);
+ }
+
+ virtual std::wstring print() const override
+ {
+ return L"[layer_consumer]";
+ }
+
+ safe_ptr<basic_frame> receive()
+ {
+ safe_ptr<basic_frame> frame;
+ if (!frame_buffer_.try_pop(frame))
+ {
+ return basic_frame::late();
+ }
+ return frame;
+ }
+};
+
+class layer_producer : public frame_producer
+{
+ monitor::subject monitor_subject_;
+
+ const safe_ptr<frame_factory> frame_factory_;
+ int layer_;
+ const std::shared_ptr<layer_consumer> consumer_;
+
+ safe_ptr<basic_frame> last_frame_;
+ uint64_t frame_number_;
+
+ const safe_ptr<stage> stage_;
+
+public:
+ explicit layer_producer(const safe_ptr<frame_factory>& frame_factory, const safe_ptr<stage>& stage, int layer)
+ : frame_factory_(frame_factory)
+ , layer_(layer)
+ , stage_(stage)
+ , consumer_(new layer_consumer())
+ , last_frame_(basic_frame::empty())
+ , frame_number_(0)
+ {
+ stage_->add_layer_consumer(this, layer_, consumer_);
+ CASPAR_LOG(info) << print() << L" Initialized";
+ }
+
+ ~layer_producer()
+ {
+ stage_->remove_layer_consumer(this, layer_);
+ CASPAR_LOG(info) << print() << L" Uninitialized";
+ }
+
+ // frame_producer
+
+ virtual safe_ptr<basic_frame> receive(int) override
+ {
+ auto consumer_frame = consumer_->receive();
+ if (consumer_frame == basic_frame::late())
+ return last_frame_;
+
+ frame_number_++;
+ return last_frame_ = consumer_frame;
+ }
+
+ virtual safe_ptr<basic_frame> last_frame() const override
+ {
+ return last_frame_;
+ }
+
+ virtual std::wstring print() const override
+ {
+ return L"layer-producer[" + boost::lexical_cast<std::wstring>(layer_) + L"]";
+ }
+
+ virtual boost::property_tree::wptree info() const override
+ {
+ boost::property_tree::wptree info;
+ info.add(L"type", L"layer-producer");
+ return info;
+ }
+
+ monitor::source& monitor_output()
+ {
+ return monitor_subject_;
+ }
+
+};
+
+safe_ptr<frame_producer> create_layer_producer(const safe_ptr<core::frame_factory>& frame_factory, const safe_ptr<stage>& stage, int layer)
+{
+ return create_producer_print_proxy(
+ make_safe<layer_producer>(frame_factory, stage, layer)
+ );
+}
+
+}}
\ No newline at end of file
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG 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 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG 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 CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Cambell Prince, cambell.prince@gmail.com
+*/
+
+#pragma once
+
+#include "../frame_producer.h"
+
+#include <string>
+#include <vector>
+
+namespace caspar { namespace core {
+
+class stage;
+struct frame_factory;
+
+safe_ptr<frame_producer> create_layer_producer(const safe_ptr<core::frame_factory>& frame_factory, const safe_ptr<stage>& stage, int layer);
+
+}}
#include <common/concurrency/executor.h>\r
\r
#include <core/producer/frame/frame_transform.h>\r
+#include <core/consumer/frame_consumer.h>\r
+#include <core/consumer/write_frame_consumer.h>\r
\r
#include <boost/foreach.hpp>\r
#include <boost/timer.hpp>\r
#include <map>\r
\r
namespace caspar { namespace core {\r
- \r
+\r
template<typename T>\r
class tweened_transform\r
{\r
monitor::subject monitor_subject_;\r
\r
executor executor_;\r
+\r
+private:\r
+ // map of layer -> map of tokens (src ref) -> layer_consumer\r
+ std::map<int, std::map<void*, std::shared_ptr<write_frame_consumer>>> layer_consumers_;\r
+\r
public:\r
implementation(const safe_ptr<diagnostics::graph>& graph, const safe_ptr<stage::target_t>& target, const video_format_desc& format_desc) \r
: graph_(graph)\r
std::weak_ptr<implementation> self = shared_from_this();\r
executor_.begin_invoke([=]{tick(self);});\r
}\r
- \r
+ \r
+ void add_layer_consumer(void* token, int layer, const std::shared_ptr<write_frame_consumer>& layer_consumer)\r
+ {\r
+ executor_.begin_invoke([=]\r
+ {\r
+ layer_consumers_[layer][token] = layer_consumer;\r
+ }, high_priority);\r
+ }\r
+\r
+ void remove_layer_consumer(void* token, int layer)\r
+ {\r
+ executor_.begin_invoke([=]\r
+ {\r
+ auto& layer_map = layer_consumers_[layer];\r
+ layer_map.erase(token);\r
+ if (layer_map.empty())\r
+ {\r
+ layer_consumers_.erase(layer);\r
+ }\r
+ }, high_priority);\r
+ }\r
+\r
void tick(const std::weak_ptr<implementation>& self)\r
{ \r
try\r
hints |= frame_producer::ALPHA_HINT;\r
\r
auto frame = layer.second->receive(hints); \r
- \r
+ auto layer_consumers_it = layer_consumers_.find(layer.first);\r
+ if (layer_consumers_it != layer_consumers_.end())\r
+ {\r
+ auto consumer_it = (*layer_consumers_it).second | boost::adaptors::map_values;\r
+ tbb::parallel_for_each(consumer_it.begin(), consumer_it.end(), [&](decltype(consumer_it[0]) layer_consumer) \r
+ {\r
+ layer_consumer->send(frame);\r
+ });\r
+ }\r
+\r
auto frame1 = make_safe<core::basic_frame>(frame);\r
frame1->get_frame_transform() = transform;\r
\r
});\r
\r
graph_->set_value("produce-time", produce_timer_.elapsed()*format_desc_.fps*0.5);\r
- \r
+\r
std::shared_ptr<void> ticket(nullptr, [self](void*)\r
{\r
auto self2 = self.lock();\r
void stage::swap_layers(const safe_ptr<stage>& other){impl_->swap_layers(*other);}\r
void stage::swap_layer(int index, size_t other_index){impl_->swap_layer(index, other_index);}\r
void stage::swap_layer(int index, size_t other_index, const safe_ptr<stage>& other){impl_->swap_layer(index, other_index, *other);}\r
+void stage::add_layer_consumer(void* token, int layer, const std::shared_ptr<write_frame_consumer>& layer_consumer){impl_->add_layer_consumer(token, layer, layer_consumer);}\r
+void stage::remove_layer_consumer(void* token, int layer){impl_->remove_layer_consumer(token, layer);}\r
boost::unique_future<safe_ptr<frame_producer>> stage::foreground(int index) {return impl_->foreground(index);}\r
boost::unique_future<safe_ptr<frame_producer>> stage::background(int index) {return impl_->background(index);}\r
boost::unique_future<std::wstring> stage::call(int index, bool foreground, const std::wstring& param){return impl_->call(index, foreground, param);}\r
\r
struct video_format_desc;\r
struct frame_transform;\r
+struct write_frame_consumer;\r
\r
class stage : boost::noncopyable\r
{\r
void swap_layers(const safe_ptr<stage>& other);\r
void swap_layer(int index, size_t other_index);\r
void swap_layer(int index, size_t other_index, const safe_ptr<stage>& other);\r
- \r
+\r
+ void add_layer_consumer(void* token, int layer, const std::shared_ptr<write_frame_consumer>& layer_consumer);\r
+ void remove_layer_consumer(void* token, int layer);\r
+\r
boost::unique_future<std::wstring> call(int index, bool foreground, const std::wstring& param);\r
\r
// Properties\r
#include <core/video_format.h>\r
#include <core/producer/transition/transition_producer.h>\r
#include <core/producer/channel/channel_producer.h>\r
+#include <core/producer/layer/layer_producer.h>\r
#include <core/producer/frame/frame_transform.h>\r
#include <core/producer/stage.h>\r
#include <core/producer/layer.h>\r
\r
/* Return codes\r
\r
-100 [action] Information om att n�got har h�nt \r
-101 [action] Information om att n�got har h�nt, en rad data skickas \r
+100 [action] Information om att något har hänt \r
+101 [action] Information om att något har hänt, en rad data skickas \r
\r
-202 [kommando] OK Kommandot har utf�rts \r
-201 [kommando] OK Kommandot har utf�rts, och en rad data skickas tillbaka \r
-200 [kommando] OK Kommandot har utf�rts, och flera rader data skickas tillbaka. Avslutas med tomrad \r
+202 [kommando] OK Kommandot har utförts \r
+201 [kommando] OK Kommandot har utförts, och en rad data skickas tillbaka \r
+200 [kommando] OK Kommandot har utförts, och flera rader data skickas tillbaka. Avslutas med tomrad \r
\r
-400 ERROR Kommandot kunde inte f�rst�s \r
+400 ERROR Kommandot kunde inte förstås \r
401 [kommando] ERROR Ogiltig kanal \r
402 [kommando] ERROR Parameter saknas \r
403 [kommando] ERROR Ogiltig parameter \r
\r
500 FAILED Internt configurationfel \r
501 [kommando] FAILED Internt configurationfel \r
-502 [kommando] FAILED Ol�slig mediafil \r
+502 [kommando] FAILED Oläslig mediafil \r
\r
600 [kommando] FAILED funktion ej implementerad\r
*/\r
\r
auto blend_str = _parameters.at(1); \r
int layer = GetLayerIndex();\r
- blend_mode::type && blend = get_blend_mode(blend_str);\r
+ blend_mode::type blend = get_blend_mode(blend_str);\r
GetChannel()->mixer()->set_blend_mode(GetLayerIndex(), blend); \r
}\r
else if(_parameters[0] == L"CHROMA")\r
}\r
\r
int layer = GetLayerIndex();\r
- chroma chroma;\r
+ chroma chroma;\r
chroma.key = get_chroma_mode(_parameters[1]);\r
\r
if (chroma.key != chroma::none)\r
}\r
}\r
\r
+safe_ptr<core::frame_producer> RouteCommand::TryCreateProducer(AMCPCommand& command, std::wstring const& uri)\r
+{\r
+ safe_ptr<core::frame_producer> pFP(frame_producer::empty());\r
+\r
+ auto tokens = core::parameters::protocol_split(uri);\r
+ auto src_channel_layer_token = tokens[0] == L"route" ? tokens[1] : uri;\r
+ std::vector<std::wstring> src_channel_layer;\r
+ boost::split(src_channel_layer, src_channel_layer_token, boost::is_any_of("-"));\r
+\r
+ if (tokens[0] == L"route" || src_channel_layer.size() == 2) // It looks like a route\r
+ {\r
+ // Find the source channel\r
+ int src_channel_index = boost::lexical_cast<int>(src_channel_layer[0]);\r
+ auto channels = command.GetChannels();\r
+ auto src_channel = std::find_if(\r
+ channels.begin(), \r
+ channels.end(), \r
+ [src_channel_index](const safe_ptr<core::video_channel>& item) { return item->index() == src_channel_index; }\r
+ );\r
+ if (src_channel == channels.end())\r
+ BOOST_THROW_EXCEPTION(null_argument() << msg_info("src channel not found"));\r
+\r
+ // Find the source layer (if one is given)\r
+ int src_layer_index = -1;\r
+ if (src_channel_layer.size() > 1 && !src_channel_layer[1].empty())\r
+ {\r
+ src_layer_index = boost::lexical_cast<int>(src_channel_layer[1]);\r
+ }\r
+\r
+ if (src_layer_index >= 0)\r
+ {\r
+ pFP = create_layer_producer(command.GetChannel()->mixer(), (*src_channel)->stage(), src_layer_index);\r
+ } else \r
+ {\r
+ pFP = create_channel_producer(command.GetChannel()->mixer(), *src_channel);\r
+ }\r
+ }\r
+ return pFP;\r
+}\r
+\r
+bool RouteCommand::DoExecute()\r
+{ \r
+ try\r
+ {\r
+ auto pFP = RouteCommand::TryCreateProducer(\r
+ *this, _parameters.at_original(0));\r
+\r
+ if (pFP != frame_producer::empty())\r
+ {\r
+ GetChannel()->stage()->load(GetLayerIndex(), pFP, true);\r
+ GetChannel()->stage()->play(GetLayerIndex());\r
+\r
+ SetReplyString(TEXT("202 ROUTE OK\r\n"));\r
+ \r
+ return true;\r
+ }\r
+ SetReplyString(TEXT("404 ROUTE ERROR\r\n"));\r
+ return false;\r
+ }\r
+ catch(file_not_found&)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ SetReplyString(TEXT("404 ROUTE ERROR\r\n"));\r
+ return false;\r
+ }\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ SetReplyString(TEXT("502 ROUTE FAILED\r\n"));\r
+ return false;\r
+ }\r
+}\r
+\r
bool LoadCommand::DoExecute()\r
{ \r
//Perform loading of the clip\r
try\r
{\r
- auto pFP = create_producer(GetChannel()->mixer(), _parameters); \r
+ auto uri_tokens = parameters::protocol_split(_parameters.at_original(0));\r
+ auto pFP = frame_producer::empty();\r
+ if (uri_tokens[0].empty() || uri_tokens[0] == L"route")\r
+ {\r
+ pFP = RouteCommand::TryCreateProducer(*this, _parameters.at_original(0));\r
+ }\r
+ if (pFP == frame_producer::empty())\r
+ {\r
+ pFP = create_producer(GetChannel()->mixer(), _parameters);\r
+ }\r
GetChannel()->stage()->load(GetLayerIndex(), pFP, true);\r
\r
SetReplyString(TEXT("202 LOAD OK\r\n"));\r
//Perform loading of the clip\r
try\r
{\r
- auto pFP = create_producer(GetChannel()->mixer(), _parameters);\r
+ auto uri_tokens = core::parameters::protocol_split(_parameters.at_original(0));\r
+ auto pFP = frame_producer::empty();\r
+ if (uri_tokens[0].empty() || uri_tokens[0] == L"route")\r
+ {\r
+ pFP = RouteCommand::TryCreateProducer(*this, _parameters.at_original(0));\r
+ }\r
+ if (pFP == frame_producer::empty())\r
+ {\r
+ pFP = create_producer(GetChannel()->mixer(), _parameters);\r
+ }\r
if(pFP == frame_producer::empty())\r
BOOST_THROW_EXCEPTION(file_not_found() << msg_info(_parameters.size() > 0 ? narrow(_parameters[0]) : ""));\r
\r
if(!_parameters.empty())\r
{\r
LoadbgCommand lbg;\r
+ lbg.SetChannels(GetChannels());\r
lbg.SetChannel(GetChannel());\r
lbg.SetChannelIndex(GetChannelIndex());\r
lbg.SetLayerIntex(GetLayerIndex());\r
#include "AMCPCommand.h"\r
\r
namespace caspar {\r
+\r
namespace core {\r
struct frame_transform;\r
+ struct frame_producer;\r
}\r
\r
namespace protocol {\r
- \r
+\r
std::wstring ListMedia();\r
std::wstring ListTemplates();\r
\r
bool DoExecute();\r
};\r
\r
+class RouteCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
+{\r
+ std::wstring print() const { return L"RouteCommand";}\r
+ bool DoExecute();\r
+public:\r
+ static safe_ptr<core::frame_producer> TryCreateProducer(AMCPCommand& command, std::wstring const& uri);\r
+};\r
+\r
+/*class RouteCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
+{\r
+ std::wstring print() const { return L"RouteCommand";}\r
+ bool DoExecute();\r
+};*/\r
+\r
class LoadCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
{\r
std::wstring print() const { return L"LoadCommand";}\r
else if(s == TEXT("CHANNEL_GRID")) return std::make_shared<ChannelGridCommand>();\r
else if(s == TEXT("CALL")) return std::make_shared<CallCommand>();\r
else if(s == TEXT("SWAP")) return std::make_shared<SwapCommand>();\r
+ else if(s == TEXT("ROUTE")) return std::make_shared<RouteCommand>();\r
else if(s == TEXT("LOAD")) return std::make_shared<LoadCommand>();\r
else if(s == TEXT("LOADBG")) return std::make_shared<LoadbgCommand>();\r
else if(s == TEXT("ADD")) return std::make_shared<AddCommand>();\r