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