Line data Source code
1 :
2 : /* Copyright (c) 2008-2017, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : *
5 : * This library is free software; you can redistribute it and/or modify it under
6 : * the terms of the GNU Lesser General Public License version 2.1 as published
7 : * by the Free Software Foundation.
8 : *
9 : * This library is distributed in the hope that it will be useful, but WITHOUT
10 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 : * details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public License
15 : * along with this library; if not, write to the Free Software Foundation, Inc.,
16 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 : */
18 :
19 : #include "view.h"
20 :
21 : #include "compositor.h"
22 : #include "config.h"
23 : #include "eventICommand.h"
24 : #include "image.h"
25 : #include "imageOp.h"
26 : #include "layout.h"
27 : #include "observer.h"
28 : #include "pipe.h"
29 : #include "server.h"
30 :
31 : #include <eq/fabric/commands.h>
32 : #include <eq/fabric/sizeEvent.h>
33 :
34 : #include <co/dataIStream.h>
35 : #include <co/dataOStream.h>
36 : #include <lunchbox/scopedMutex.h>
37 : #include <lunchbox/spinLock.h>
38 :
39 : namespace eq
40 : {
41 : namespace detail
42 : {
43 16 : class View
44 : {
45 : public:
46 : lunchbox::SpinLock eventLock; //!< event-handling resize synchronizer
47 :
48 : /** Unmodified, baseline view frustum data, used for resizing. */
49 : Frustum baseFrustum;
50 :
51 0 : struct Screenshot
52 : {
53 : std::unique_ptr<eq::Image> _image;
54 : Viewport _viewport;
55 :
56 0 : bool isComplete() const { return _viewport == Viewport::FULL; }
57 0 : void composite(const Viewport& viewport, const eq::Image& image)
58 : {
59 0 : if (!_image)
60 : {
61 0 : _viewport = viewport;
62 0 : _image.reset(new eq::Image(image));
63 0 : return;
64 : }
65 :
66 0 : ImageOps ops;
67 0 : ImageOp current;
68 0 : current.image = _image.get();
69 0 : ImageOp newImage;
70 0 : newImage.image = ℑ
71 :
72 0 : ops.push_back(current);
73 0 : ops.push_back(newImage);
74 0 : _image.reset(
75 0 : new eq::Image(*Compositor::mergeImagesCPU(ops, false)));
76 0 : _viewport.unite(viewport);
77 : }
78 : };
79 :
80 : std::map<uint32_t, Screenshot> screenshot;
81 : eq::View::ScreenshotFunc screenshotFunc;
82 : };
83 : }
84 :
85 : typedef fabric::View<Layout, View, Observer> Super;
86 :
87 8 : View::View(Layout* parent)
88 : : Super(parent)
89 8 : , _impl(new detail::View)
90 16 : , _pipe(0)
91 : {
92 8 : }
93 :
94 16 : View::~View()
95 : {
96 8 : delete _impl;
97 8 : }
98 :
99 28 : void View::deserialize(co::DataIStream& is, const uint64_t dirtyBits)
100 : {
101 28 : Super::deserialize(is, dirtyBits);
102 36 : if (_impl->baseFrustum.getCurrentType() == TYPE_NONE &&
103 8 : (dirtyBits & DIRTY_FRUSTUM))
104 : {
105 8 : _impl->baseFrustum = *this; // save baseline data for resizing
106 : }
107 28 : }
108 :
109 8 : void View::detach()
110 : {
111 : // if pipe is not running, detach comes from _flushViews in state stopping
112 : // Don't send command to stopping pipe (see issue #11)
113 8 : if (_pipe && _pipe->isRunning())
114 : {
115 : // local command dispatching
116 0 : co::ObjectOCommand(_pipe, getLocalNode(), fabric::CMD_PIPE_DETACH_VIEW,
117 0 : co::COMMANDTYPE_OBJECT, _pipe->getID(),
118 : CO_INSTANCE_ALL)
119 0 : << getID();
120 : }
121 8 : Super::detach();
122 8 : }
123 :
124 14 : Config* View::getConfig()
125 : {
126 14 : Layout* layout = getLayout();
127 14 : if (layout)
128 14 : return layout->getConfig();
129 :
130 0 : if (_pipe)
131 0 : return _pipe->getConfig();
132 :
133 0 : LBUNREACHABLE;
134 0 : return 0;
135 : }
136 :
137 7 : const Config* View::getConfig() const
138 : {
139 7 : const Layout* layout = getLayout();
140 7 : if (layout)
141 7 : return layout->getConfig();
142 :
143 0 : if (_pipe)
144 0 : return _pipe->getConfig();
145 :
146 0 : LBUNREACHABLE;
147 0 : return 0;
148 : }
149 :
150 0 : ServerPtr View::getServer()
151 : {
152 0 : Config* config = getConfig();
153 0 : LBASSERT(config);
154 0 : return (config ? config->getServer() : 0);
155 : }
156 :
157 0 : const Frustum& View::getBaseFrustum() const
158 : {
159 0 : return _impl->baseFrustum;
160 : }
161 :
162 0 : bool View::handleEvent(const EventType type, const SizeEvent& event)
163 : {
164 0 : if (type != EVENT_VIEW_RESIZE)
165 0 : return false;
166 :
167 0 : if (event.dw == 0.f || event.dh == 0.f)
168 0 : return true;
169 :
170 0 : switch (getCurrentType())
171 : {
172 : case TYPE_WALL:
173 : {
174 0 : const float ratio(event.dw / event.dh);
175 0 : Wall wall(_impl->baseFrustum.getWall());
176 0 : wall.resizeHorizontal(ratio);
177 :
178 0 : lunchbox::ScopedFastWrite mutex(_impl->eventLock);
179 0 : setWall(wall);
180 0 : return true;
181 : }
182 :
183 : case View::TYPE_PROJECTION:
184 : {
185 0 : const float ratio(event.dw / event.dh);
186 0 : eq::Projection projection(_impl->baseFrustum.getProjection());
187 0 : projection.resizeHorizontal(ratio);
188 :
189 0 : lunchbox::ScopedFastWrite mutex(_impl->eventLock);
190 0 : setProjection(projection);
191 0 : return true;
192 : }
193 :
194 : default:
195 0 : LBUNIMPLEMENTED;
196 : case eq::View::TYPE_NONE:
197 0 : return false;
198 : }
199 : }
200 :
201 0 : void View::enableScreenshot(Frame::Buffer buffers, const ScreenshotFunc& func)
202 : {
203 0 : Super::_setScreenshotBuffers(buffers);
204 0 : _impl->screenshotFunc = func;
205 0 : }
206 :
207 0 : void View::disableScreenshot()
208 : {
209 0 : Super::_setScreenshotBuffers(Frame::Buffer::none);
210 0 : }
211 :
212 0 : void View::sendScreenshotEvent(const Viewport& viewport,
213 : const uint32_t frameNumber, const Image& image)
214 : {
215 0 : getConfig()->sendEvent(EVENT_VIEW_SCREENSHOT) << getID() << viewport
216 0 : << frameNumber << image;
217 0 : }
218 :
219 0 : bool View::handleEvent(EventICommand& command)
220 : {
221 0 : switch (command.getEventType())
222 : {
223 : case EVENT_VIEW_SCREENSHOT:
224 0 : return _handleScreenshot(command);
225 : }
226 0 : return false;
227 : }
228 :
229 0 : bool View::_handleScreenshot(EventICommand& command)
230 : {
231 0 : const auto& vp = command.read<Viewport>();
232 0 : const auto frameNumber = command.read<uint32_t>();
233 0 : const auto& newImage = command.read<Image>();
234 :
235 0 : auto& screenshot = _impl->screenshot[frameNumber];
236 0 : screenshot.composite(vp, newImage);
237 :
238 0 : if (screenshot.isComplete())
239 : {
240 0 : _impl->screenshotFunc(frameNumber, *screenshot._image);
241 0 : _impl->screenshot.erase(frameNumber);
242 : }
243 :
244 0 : return true;
245 : }
246 : }
247 :
248 : #include <eq/fabric/view.ipp>
249 : template class eq::fabric::View<eq::Layout, eq::View, eq::Observer>;
250 :
251 : /** @cond IGNORE */
252 : template EQFABRIC_API std::ostream& eq::fabric::operator<<(std::ostream&,
253 30 : const eq::Super&);
254 : /** @endcond */
|