]> 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 "scene_producer.h"
25
26 #include "../../frame/draw_frame.h"
27 #include "../../interaction/interaction_aggregator.h"
28
29 namespace caspar { namespace core { namespace scene {
30
31 layer::layer(const spl::shared_ptr<frame_producer>& producer)
32         : producer(producer)
33 {
34 }
35
36 adjustments::adjustments()
37         : opacity(1.0)
38 {
39 }
40
41 struct scene_producer::impl
42 {
43         constraints pixel_constraints_;
44         std::vector<layer> layers_;
45         interaction_aggregator aggregator_;
46
47         impl(int width, int height)
48                 : pixel_constraints_(width, height)
49                 , aggregator_([=] (double x, double y) { return collission_detect(x, y); })
50         {
51         }
52
53         layer& create_layer(
54                         const spl::shared_ptr<frame_producer>& producer, int x, int y)
55         {
56                 layer layer(producer);
57
58                 layer.position.x.set(x);
59                 layer.position.y.set(y);
60
61                 layers_.push_back(layer);
62
63                 return layers_.back();
64         }
65
66         frame_transform get_transform(const layer& layer) const
67         {
68                 frame_transform transform;
69
70                 auto& pos = transform.image_transform.fill_translation;
71                 auto& scale = transform.image_transform.fill_scale;
72
73                 pos[0] = static_cast<double>(layer.position.x.get()) / static_cast<double>(pixel_constraints_.width.get());
74                 pos[1] = static_cast<double>(layer.position.y.get()) / static_cast<double>(pixel_constraints_.height.get());
75                 scale[0] = static_cast<double>(layer.producer.get()->pixel_constraints().width.get())
76                                 / static_cast<double>(pixel_constraints_.width.get());
77                 scale[1] = static_cast<double>(layer.producer.get()->pixel_constraints().height.get())
78                                 / static_cast<double>(pixel_constraints_.height.get());
79
80                 transform.image_transform.opacity = layer.adjustments.opacity.get();
81                 transform.image_transform.is_key = layer.is_key.get();
82
83                 return transform;
84         }
85
86         draw_frame render_frame()
87         {
88                 std::vector<draw_frame> frames;
89
90                 BOOST_FOREACH(auto& layer, layers_)
91                 {
92                         draw_frame frame(layer.producer.get()->receive());
93                         frame.transform() = get_transform(layer);;
94                         frames.push_back(frame);
95                 }
96
97                 return draw_frame(frames);
98         }
99
100         void on_interaction(const interaction_event::ptr& event)
101         {
102                 aggregator_.translate_and_send(event);
103         }
104
105         bool collides(double x, double y) const
106         {
107                 return collission_detect(x, y);
108         }
109
110         boost::optional<interaction_target> collission_detect(double x, double y) const
111         {
112                 BOOST_FOREACH(auto& layer, layers_ | boost::adaptors::reversed)
113                 {
114                         auto transform = get_transform(layer);
115                         auto translated = translate(x, y, transform);
116
117                         if (translated.first >= 0.0
118                                 && translated.first <= 1.0
119                                 && translated.second >= 0.0
120                                 && translated.second <= 1.0
121                                 && layer.producer.get()->collides(translated.first, translated.second))
122                         {
123                                 return std::make_pair(transform, layer.producer.get().get());
124                         }
125                 }
126
127                 return boost::optional<interaction_target>();
128         }
129
130         std::wstring print() const
131         {
132                 return L"scene[]";
133         }
134
135         std::wstring name() const
136         {
137                 return L"scene";
138         }
139         
140         boost::property_tree::wptree info() const
141         {
142                 boost::property_tree::wptree info;
143                 info.add(L"type", L"scene");
144                 return info;
145         }
146
147         void subscribe(const monitor::observable::observer_ptr& o)
148         {
149         }
150
151         void unsubscribe(const monitor::observable::observer_ptr& o)
152         {
153         }
154 };
155
156 scene_producer::scene_producer(int width, int height)
157         : impl_(new impl(width, height))
158 {
159 }
160
161 scene_producer::~scene_producer()
162 {
163 }
164
165 layer& scene_producer::create_layer(
166                 const spl::shared_ptr<frame_producer>& producer, int x, int y)
167 {
168         return impl_->create_layer(producer, x, y);
169 }
170
171 draw_frame scene_producer::receive_impl()
172 {
173         return impl_->render_frame();
174 }
175
176 constraints& scene_producer::pixel_constraints() { return impl_->pixel_constraints_; }
177
178 void scene_producer::on_interaction(const interaction_event::ptr& event)
179 {
180         impl_->on_interaction(event);
181 }
182
183 bool scene_producer::collides(double x, double y) const
184 {
185         return impl_->collides(x, y);
186 }
187
188 std::wstring scene_producer::print() const
189 {
190         return impl_->print();
191 }
192
193 std::wstring scene_producer::name() const
194 {
195         return impl_->name();
196 }
197
198 boost::property_tree::wptree scene_producer::info() const
199 {
200         return impl_->info();
201 }
202
203 void scene_producer::subscribe(const monitor::observable::observer_ptr& o)
204 {
205         impl_->subscribe(o);
206 }
207
208 void scene_producer::unsubscribe(const monitor::observable::observer_ptr& o)
209 {
210         impl_->unsubscribe(o);
211 }
212
213 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)
214 {
215         if (params.size() < 1 || params.at(0) != L"[SCENE]")
216                 return core::frame_producer::empty();
217
218         auto scene = spl::make_shared<scene_producer>(160, 90);
219
220         std::vector<std::wstring> sub_params;
221
222         binding<int> text_width(10);
223         binding<int> padding(1);
224         binding<int> panel_width = padding + text_width + padding;
225
226         auto subscription = panel_width.on_change([&]
227         {
228                 CASPAR_LOG(info) << "Panel width: " << panel_width.get();
229         });
230
231         text_width.set(20);
232         text_width.set(10);
233         padding.set(2);
234         text_width.set(20);
235
236         sub_params.push_back(L"[FREEHAND]");
237         sub_params.push_back(L"100");
238         sub_params.push_back(L"50");
239         scene->create_layer(create_producer(frame_factory, format_desc, sub_params), 10, 10);
240         sub_params.clear();
241
242         sub_params.push_back(L"BLUE");
243         scene->create_layer(create_producer(frame_factory, format_desc, sub_params), 110, 10);
244         sub_params.clear();
245
246         sub_params.push_back(L"SP");
247         scene->create_layer(create_producer(frame_factory, format_desc, sub_params), 50, 50);
248         sub_params.clear();
249
250         return scene;
251 }
252
253 }}}