]> git.sesse.net Git - casparcg/blob - core/producer/scene/scene_producer.cpp
Added support for psd placeholder layer
[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         std::map<std::wstring, std::shared_ptr<parameter_holder_base>> parameters_;
56
57         impl(int width, int height)
58                 : pixel_constraints_(width, height)
59                 , aggregator_([=] (double x, double y) { return collission_detect(x, y); })
60         {
61         }
62
63         layer& create_layer(
64                         const spl::shared_ptr<frame_producer>& producer, int x, int y, const std::wstring& name)
65         {
66                 layer& layer = create_layer(producer, x, y);
67                 layer.name.set(name);
68
69                 return layer;
70         }
71
72         layer& create_layer(
73                         const spl::shared_ptr<frame_producer>& producer, int x, int y)
74         {
75                 layer& layer = create_layer(producer);
76
77                 layer.position.x.set(x);
78                 layer.position.y.set(y);
79
80                 return layer;
81         }
82
83         layer& create_layer(const spl::shared_ptr<frame_producer>& producer)
84         {
85                 layer layer(producer);
86
87                 layers_.push_back(layer);
88
89                 return layers_.back();
90         }
91
92         void store_parameter(
93                         const std::wstring& name,
94                         const std::shared_ptr<parameter_holder_base>& param)
95         {
96                 parameters_.insert(std::make_pair(boost::to_lower_copy(name), param));
97         }
98
99         binding<int64_t> frame()
100         {
101                 return frame_number_;
102         }
103
104         frame_transform get_transform(const layer& layer) const
105         {
106                 frame_transform transform;
107
108                 auto& pos = transform.image_transform.fill_translation;
109                 auto& scale = transform.image_transform.fill_scale;
110
111                 pos[0] = static_cast<double>(layer.position.x.get()) / static_cast<double>(pixel_constraints_.width.get());
112                 pos[1] = static_cast<double>(layer.position.y.get()) / static_cast<double>(pixel_constraints_.height.get());
113                 scale[0] = static_cast<double>(layer.producer.get()->pixel_constraints().width.get())
114                                 / static_cast<double>(pixel_constraints_.width.get());
115                 scale[1] = static_cast<double>(layer.producer.get()->pixel_constraints().height.get())
116                                 / static_cast<double>(pixel_constraints_.height.get());
117
118                 transform.image_transform.opacity = layer.adjustments.opacity.get();
119                 transform.image_transform.is_key = layer.is_key.get();
120
121                 return transform;
122         }
123
124         draw_frame render_frame()
125         {
126                 std::vector<draw_frame> frames;
127
128                 BOOST_FOREACH(auto& layer, layers_)
129                 {
130                         if (layer.hidden.get())
131                                 continue;
132
133                         draw_frame frame(layer.producer.get()->receive());
134                         frame.transform() = get_transform(layer);;
135                         frames.push_back(frame);
136                 }
137
138                 ++frame_number_;
139
140                 return draw_frame(frames);
141         }
142
143         void on_interaction(const interaction_event::ptr& event)
144         {
145                 aggregator_.translate_and_send(event);
146         }
147
148         bool collides(double x, double y) const
149         {
150                 return collission_detect(x, y);
151         }
152
153         boost::optional<interaction_target> collission_detect(double x, double y) const
154         {
155                 BOOST_FOREACH(auto& layer, layers_ | boost::adaptors::reversed)
156                 {
157                         if (layer.hidden.get())
158                                 continue;
159
160                         auto transform = get_transform(layer);
161                         auto translated = translate(x, y, transform);
162
163                         if (translated.first >= 0.0
164                                 && translated.first <= 1.0
165                                 && translated.second >= 0.0
166                                 && translated.second <= 1.0
167                                 && layer.producer.get()->collides(translated.first, translated.second))
168                         {
169                                 return std::make_pair(transform, layer.producer.get().get());
170                         }
171                 }
172
173                 return boost::optional<interaction_target>();
174         }
175
176         boost::unique_future<std::wstring> call(const std::vector<std::wstring>& params) 
177         {
178                 for (int i = 0; i + 1 < params.size(); i += 2)
179                 {
180                         auto found = parameters_.find(boost::to_lower_copy(params[i]));
181
182                         if (found != parameters_.end())
183                                 found->second->set(params[i + 1]);
184                 }
185
186                 return wrap_as_future(std::wstring(L""));
187         }
188
189         std::wstring print() const
190         {
191                 return L"scene[]";
192         }
193
194         std::wstring name() const
195         {
196                 return L"scene";
197         }
198         
199         boost::property_tree::wptree info() const
200         {
201                 boost::property_tree::wptree info;
202                 info.add(L"type", L"scene");
203                 return info;
204         }
205
206         void subscribe(const monitor::observable::observer_ptr& o)
207         {
208         }
209
210         void unsubscribe(const monitor::observable::observer_ptr& o)
211         {
212         }
213 };
214
215 scene_producer::scene_producer(int width, int height)
216         : impl_(new impl(width, height))
217 {
218 }
219
220 scene_producer::~scene_producer()
221 {
222 }
223
224 layer& scene_producer::create_layer(
225                 const spl::shared_ptr<frame_producer>& producer, int x, int y)
226 {
227         return impl_->create_layer(producer, x, y);
228 }
229
230 layer& scene_producer::create_layer(
231                 const spl::shared_ptr<frame_producer>& producer, int x, int y, const std::wstring& name)
232 {
233         return impl_->create_layer(producer, x, y, name);
234 }
235
236 layer& scene_producer::create_layer(
237                 const spl::shared_ptr<frame_producer>& producer)
238 {
239         return impl_->create_layer(producer);
240 }
241
242 binding<int64_t> scene_producer::frame()
243 {
244         return impl_->frame();
245 }
246
247 draw_frame scene_producer::receive_impl()
248 {
249         return impl_->render_frame();
250 }
251
252 constraints& scene_producer::pixel_constraints() { return impl_->pixel_constraints_; }
253
254 void scene_producer::on_interaction(const interaction_event::ptr& event)
255 {
256         impl_->on_interaction(event);
257 }
258
259 bool scene_producer::collides(double x, double y) const
260 {
261         return impl_->collides(x, y);
262 }
263
264 std::wstring scene_producer::print() const
265 {
266         return impl_->print();
267 }
268
269 std::wstring scene_producer::name() const
270 {
271         return impl_->name();
272 }
273
274 boost::property_tree::wptree scene_producer::info() const
275 {
276         return impl_->info();
277 }
278
279 boost::unique_future<std::wstring> scene_producer::call(const std::vector<std::wstring>& params) 
280 {
281         return impl_->call(params);
282 }
283
284 void scene_producer::subscribe(const monitor::observable::observer_ptr& o)
285 {
286         impl_->subscribe(o);
287 }
288
289 void scene_producer::unsubscribe(const monitor::observable::observer_ptr& o)
290 {
291         impl_->unsubscribe(o);
292 }
293
294 void scene_producer::store_parameter(
295                 const std::wstring& name,
296                 const std::shared_ptr<parameter_holder_base>& param)
297 {
298         impl_->store_parameter(name, param);
299 }
300
301 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)
302 {
303         if (params.size() < 1 || !boost::iequals(params.at(0), L"[SCENE]"))
304                 return core::frame_producer::empty();
305
306         auto scene = spl::make_shared<scene_producer>(format_desc.width, format_desc.height);
307
308         binding<double> text_width(10);
309         binding<double> padding(1);
310         binding<double> panel_width = padding + text_width + padding;
311         binding<double> panel_height(50);
312
313         auto subscription = panel_width.on_change([&]
314         {
315                 CASPAR_LOG(info) << "Panel width: " << panel_width.get();
316         });
317
318         text_width.set(20);
319         text_width.set(10);
320         padding.set(2);
321         text_width.set(20);
322
323         auto create_param = [](std::wstring elem) -> std::vector<std::wstring>
324         {
325                 std::vector<std::wstring> result;
326                 result.push_back(elem);
327                 return result;
328         };
329
330         auto& car_layer = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"car")));
331         car_layer.hidden = scene->frame() % 50 > 25 || !(scene->frame() < 1000);
332         std::vector<std::wstring> sub_params;
333         sub_params.push_back(L"[FREEHAND]");
334         sub_params.push_back(L"640");
335         sub_params.push_back(L"360");
336         scene->create_layer(create_producer(frame_factory, format_desc, sub_params), 10, 10);
337         sub_params.clear();
338
339         scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"BLUE")), 110, 10);
340
341         //scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"SP")), 50, 50);
342
343         auto& upper_left = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/upper_left")));
344         auto& upper_right = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/upper_right")));
345         auto& lower_left = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/lower_left")));
346         auto& lower_right = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/lower_right")));
347
348         /*
349         binding<double> panel_x = (scene->frame()
350                         .as<double>()
351                         .transformed([](double v) { return std::sin(v / 20.0); })
352                         * 20.0
353                         + 40.0)
354                         .transformed([](double v) { return std::floor(v); }); // snap to pixels instead of subpixels
355                         */
356         tweener tween(L"easeinoutsine");
357         binding<double> panel_x = when(scene->frame() < 50)
358                 .then(scene->frame().as<double>().transformed([tween](double t) { return tween(t, 0.0, 200, 50); }))
359                 .otherwise(200.0);
360         //binding<double> panel_y = when(car_layer.hidden).then(500.0).otherwise(-panel_x + 300);
361         binding<double> panel_y(500.0);
362         upper_left.position.x = panel_x;
363         upper_left.position.y = panel_y;
364         upper_right.position.x = upper_left.position.x + upper_left.producer.get()->pixel_constraints().width + panel_width;
365         upper_right.position.y = upper_left.position.y;
366         lower_left.position.x = upper_left.position.x;
367         lower_left.position.y = upper_left.position.y + upper_left.producer.get()->pixel_constraints().height + panel_height;
368         lower_right.position.x = upper_right.position.x;
369         lower_right.position.y = lower_left.position.y;
370
371         text_width.set(500);
372         panel_height.set(50);
373
374         return scene;
375 }
376
377 }}}