]> git.sesse.net Git - casparcg/blob - core/producer/scene/scene_producer.cpp
Merge branch '2.1.0' of https://github.com/CasparCG/Server into 2.1.0
[casparcg] / core / producer / scene / scene_producer.cpp
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Helge Norberg, helge.norberg@svt.se
20 */
21
22 #include "../../stdafx.h"
23
24 #include <common/future.h>
25 #include <boost/algorithm/string/split.hpp>
26 #include <boost/algorithm/string.hpp>
27
28 #include "scene_producer.h"
29
30 #include "../../frame/draw_frame.h"
31 #include "../../interaction/interaction_aggregator.h"
32
33 namespace caspar { namespace core { namespace scene {
34
35 layer::layer(const spl::shared_ptr<frame_producer>& producer)
36         : producer(producer)
37 {
38 }
39 layer::layer(const std::wstring& name, const spl::shared_ptr<frame_producer>& producer)
40         : name(name), producer(producer)
41 {
42 }
43
44 adjustments::adjustments()
45         : opacity(1.0)
46 {
47 }
48
49 struct scene_producer::impl
50 {
51         constraints pixel_constraints_;
52         std::list<layer> layers_;
53         interaction_aggregator aggregator_;
54         binding<int64_t> frame_number_;
55
56         impl(int width, int height)
57                 : pixel_constraints_(width, height)
58                 , aggregator_([=] (double x, double y) { return collission_detect(x, y); })
59         {
60         }
61
62         layer& create_layer(
63                         const spl::shared_ptr<frame_producer>& producer, int x, int y, const std::wstring& name)
64         {
65                 layer& layer = create_layer(producer, x, y);
66                 layer.name.set(name);
67
68                 return layer;
69         }
70
71         layer& create_layer(
72                         const spl::shared_ptr<frame_producer>& producer, int x, int y)
73         {
74                 layer& layer = create_layer(producer);
75
76                 layer.position.x.set(x);
77                 layer.position.y.set(y);
78
79                 return layer;
80         }
81
82         layer& create_layer(const spl::shared_ptr<frame_producer>& producer)
83         {
84                 layer layer(producer);
85
86                 layers_.push_back(layer);
87
88                 return layers_.back();
89         }
90
91         binding<int64_t> frame()
92         {
93                 return frame_number_;
94         }
95
96         frame_transform get_transform(const layer& layer) const
97         {
98                 frame_transform transform;
99
100                 auto& pos = transform.image_transform.fill_translation;
101                 auto& scale = transform.image_transform.fill_scale;
102
103                 pos[0] = static_cast<double>(layer.position.x.get()) / static_cast<double>(pixel_constraints_.width.get());
104                 pos[1] = static_cast<double>(layer.position.y.get()) / static_cast<double>(pixel_constraints_.height.get());
105                 scale[0] = static_cast<double>(layer.producer.get()->pixel_constraints().width.get())
106                                 / static_cast<double>(pixel_constraints_.width.get());
107                 scale[1] = static_cast<double>(layer.producer.get()->pixel_constraints().height.get())
108                                 / static_cast<double>(pixel_constraints_.height.get());
109
110                 transform.image_transform.opacity = layer.adjustments.opacity.get();
111                 transform.image_transform.is_key = layer.is_key.get();
112
113                 return transform;
114         }
115
116         draw_frame render_frame()
117         {
118                 std::vector<draw_frame> frames;
119
120                 BOOST_FOREACH(auto& layer, layers_)
121                 {
122                         if (layer.hidden.get())
123                                 continue;
124
125                         draw_frame frame(layer.producer.get()->receive());
126                         frame.transform() = get_transform(layer);;
127                         frames.push_back(frame);
128                 }
129
130                 frame_number_.set(frame_number_.get() + 1);
131
132                 return draw_frame(frames);
133         }
134
135         void on_interaction(const interaction_event::ptr& event)
136         {
137                 aggregator_.translate_and_send(event);
138         }
139
140         bool collides(double x, double y) const
141         {
142                 return collission_detect(x, y);
143         }
144
145         boost::optional<interaction_target> collission_detect(double x, double y) const
146         {
147                 BOOST_FOREACH(auto& layer, layers_ | boost::adaptors::reversed)
148                 {
149                         if (layer.hidden.get())
150                                 continue;
151
152                         auto transform = get_transform(layer);
153                         auto translated = translate(x, y, transform);
154
155                         if (translated.first >= 0.0
156                                 && translated.first <= 1.0
157                                 && translated.second >= 0.0
158                                 && translated.second <= 1.0
159                                 && layer.producer.get()->collides(translated.first, translated.second))
160                         {
161                                 return std::make_pair(transform, layer.producer.get().get());
162                         }
163                 }
164
165                 return boost::optional<interaction_target>();
166         }
167
168         boost::unique_future<std::wstring> call(const std::vector<std::wstring>& params) 
169         {
170                 std::wstring result;
171                 
172                 if(params.size() >= 2)
173                 {
174                         struct layer_comparer
175                         {
176                                 const std::wstring& str;
177                                 explicit layer_comparer(const std::wstring& s) : str(s) {}
178                                 bool operator()(const layer& val) { return boost::iequals(val.name.get(), str); }
179                         };
180
181                         auto it = std::find_if(layers_.begin(), layers_.end(), layer_comparer(params[0]));
182                         if(it != layers_.end())
183                         {
184                                 auto params2 = params;
185                                 params2.erase(params2.cbegin());
186                                 (*it).producer.get()->call(params2);
187                         }
188                 }
189
190                 return async(launch::deferred, [=]{return result;});
191         }
192
193         std::wstring print() const
194         {
195                 return L"scene[]";
196         }
197
198         std::wstring name() const
199         {
200                 return L"scene";
201         }
202         
203         boost::property_tree::wptree info() const
204         {
205                 boost::property_tree::wptree info;
206                 info.add(L"type", L"scene");
207                 return info;
208         }
209
210         void subscribe(const monitor::observable::observer_ptr& o)
211         {
212         }
213
214         void unsubscribe(const monitor::observable::observer_ptr& o)
215         {
216         }
217 };
218
219 scene_producer::scene_producer(int width, int height)
220         : impl_(new impl(width, height))
221 {
222 }
223
224 scene_producer::~scene_producer()
225 {
226 }
227
228 layer& scene_producer::create_layer(
229                 const spl::shared_ptr<frame_producer>& producer, int x, int y)
230 {
231         return impl_->create_layer(producer, x, y);
232 }
233
234 layer& scene_producer::create_layer(
235                 const spl::shared_ptr<frame_producer>& producer, int x, int y, const std::wstring& name)
236 {
237         return impl_->create_layer(producer, x, y, name);
238 }
239
240 layer& scene_producer::create_layer(
241                 const spl::shared_ptr<frame_producer>& producer)
242 {
243         return impl_->create_layer(producer);
244 }
245
246 binding<int64_t> scene_producer::frame()
247 {
248         return impl_->frame();
249 }
250
251 draw_frame scene_producer::receive_impl()
252 {
253         return impl_->render_frame();
254 }
255
256 constraints& scene_producer::pixel_constraints() { return impl_->pixel_constraints_; }
257
258 void scene_producer::on_interaction(const interaction_event::ptr& event)
259 {
260         impl_->on_interaction(event);
261 }
262
263 bool scene_producer::collides(double x, double y) const
264 {
265         return impl_->collides(x, y);
266 }
267
268 std::wstring scene_producer::print() const
269 {
270         return impl_->print();
271 }
272
273 std::wstring scene_producer::name() const
274 {
275         return impl_->name();
276 }
277
278 boost::property_tree::wptree scene_producer::info() const
279 {
280         return impl_->info();
281 }
282
283 boost::unique_future<std::wstring> scene_producer::call(const std::vector<std::wstring>& params) 
284 {
285         return impl_->call(params);
286 }
287
288 void scene_producer::subscribe(const monitor::observable::observer_ptr& o)
289 {
290         impl_->subscribe(o);
291 }
292
293 void scene_producer::unsubscribe(const monitor::observable::observer_ptr& o)
294 {
295         impl_->unsubscribe(o);
296 }
297
298 spl::shared_ptr<frame_producer> create_dummy_scene_producer(const spl::shared_ptr<class frame_factory>& frame_factory, const video_format_desc& format_desc, const std::vector<std::wstring>& params)
299 {
300         if (params.size() < 1 || params.at(0) != L"[SCENE]")
301                 return core::frame_producer::empty();
302
303         auto scene = spl::make_shared<scene_producer>(format_desc.width, format_desc.height);
304
305         binding<double> text_width(10);
306         binding<double> padding(1);
307         binding<double> panel_width = padding + text_width + padding;
308         binding<double> panel_height(50);
309
310         auto subscription = panel_width.on_change([&]
311         {
312                 CASPAR_LOG(info) << "Panel width: " << panel_width.get();
313         });
314
315         text_width.set(20);
316         text_width.set(10);
317         padding.set(2);
318         text_width.set(20);
319
320         auto create_param = [](std::wstring elem) -> std::vector<std::wstring>
321         {
322                 std::vector<std::wstring> result;
323                 result.push_back(elem);
324                 return result;
325         };
326
327         auto& car_layer = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"car")));
328         car_layer.hidden = scene->frame() % 50 > 25 || !(scene->frame() < 1000);
329         std::vector<std::wstring> sub_params;
330         sub_params.push_back(L"[FREEHAND]");
331         sub_params.push_back(L"640");
332         sub_params.push_back(L"360");
333         scene->create_layer(create_producer(frame_factory, format_desc, sub_params), 10, 10);
334         sub_params.clear();
335
336         scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"BLUE")), 110, 10);
337
338         //scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"SP")), 50, 50);
339
340         auto& upper_left = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/upper_left")));
341         auto& upper_right = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/upper_right")));
342         auto& lower_left = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/lower_left")));
343         auto& lower_right = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/lower_right")));
344
345         binding<double> panel_x = (scene->frame()
346                         .as<double>()
347                         .transformed([](double v) { return std::sin(v / 20.0); })
348                         * 20.0
349                         + 40.0)
350                         .transformed([](double v) { return std::floor(v); }); // snap to pixels instead of subpixels
351         binding<double> panel_y = when(car_layer.hidden).then(500.0).otherwise(-panel_x + 300);
352         upper_left.position.x = panel_x;
353         upper_left.position.y = panel_y;
354         upper_right.position.x = upper_left.position.x + upper_left.producer.get()->pixel_constraints().width + panel_width;
355         upper_right.position.y = upper_left.position.y;
356         lower_left.position.x = upper_left.position.x;
357         lower_left.position.y = upper_left.position.y + upper_left.producer.get()->pixel_constraints().height + panel_height;
358         lower_right.position.x = upper_right.position.x;
359         lower_right.position.y = lower_left.position.y;
360
361         text_width.set(500);
362         panel_height.set(50);
363
364         return scene;
365 }
366
367 }}}