Line data Source code
1 :
2 : /* Copyright (c) 2009-2013, Stefan Eilemann <eile@equalizergraphics.com>
3 : * 2011-2012, Daniel Nachbaur <danielnachbaur@gmail.com>
4 : * 2010, Cedric Stalder <cedric.stalder@gmail.com
5 : *
6 : * This library is free software; you can redistribute it and/or modify it under
7 : * the terms of the GNU Lesser General Public License version 2.1 as published
8 : * by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, write to the Free Software Foundation, Inc.,
17 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include "view.h"
21 :
22 : #include "canvas.h"
23 : #include "channel.h"
24 : #include "compound.h"
25 : #include "config.h"
26 : #include "configDestCompoundVisitor.h"
27 : #include "layout.h"
28 : #include "log.h"
29 : #include "observer.h"
30 : #include "segment.h"
31 : #include "equalizers/equalizer.h"
32 : #include "equalizers/tileEqualizer.h"
33 : #include "tileQueue.h"
34 :
35 : #include <eq/fabric/commands.h>
36 : #include <eq/fabric/paths.h>
37 :
38 : #include <co/dataIStream.h>
39 : #include <co/dataOStream.h>
40 : #include <co/iCommand.h>
41 :
42 : namespace eq
43 : {
44 : namespace server
45 : {
46 : typedef fabric::View< Layout, View, Observer > Super;
47 : typedef co::CommandFunc<View> ViewFunc;
48 :
49 414 : View::View( Layout* parent )
50 414 : : Super( parent )
51 : {
52 414 : }
53 :
54 1239 : View::~View()
55 : {
56 : // Use copy - Channel::unsetOutput modifies vector
57 413 : Channels channels = _channels;
58 1239 : for( Channels::const_iterator i = channels.begin();
59 826 : i != channels.end(); ++i )
60 : {
61 0 : Channel* channel = *i;
62 0 : channel->unsetOutput();
63 : }
64 :
65 413 : LBASSERT( _channels.empty( ));
66 413 : _channels.clear();
67 826 : }
68 :
69 : namespace
70 : {
71 : class FrustumUpdater : public ConfigVisitor
72 : {
73 : public:
74 368 : FrustumUpdater( const Channels& channels, const Vector3f& eye,
75 : const float ratio )
76 : : _channels( channels )
77 : , _eye( eye )
78 368 : , _ratio( ratio )
79 368 : {}
80 368 : virtual ~FrustumUpdater() {}
81 :
82 5624 : virtual VisitorResult visit( Compound* compound )
83 : {
84 5624 : const Channel* channel = compound->getChannel();
85 5624 : if( !channel )
86 2812 : return TRAVERSE_CONTINUE;
87 :
88 2812 : if( !compound->isDestination( ))
89 0 : return TRAVERSE_PRUNE; // only change destination compounds
90 :
91 2812 : if( std::find( _channels.begin(), _channels.end(), channel ) !=
92 2812 : _channels.end( )) // our destination channel
93 : {
94 368 : compound->updateFrustum( _eye, _ratio );
95 : }
96 :
97 2812 : return TRAVERSE_PRUNE;
98 : }
99 : private:
100 : const Channels& _channels;
101 : const Vector3f& _eye;
102 : const float _ratio;
103 : };
104 :
105 : class CapabilitiesUpdater : public ConfigVisitor
106 : {
107 : public:
108 0 : CapabilitiesUpdater( View* view )
109 : : _view( view )
110 0 : , _capabilities( _view->getMaximumCapabilities( ))
111 0 : {}
112 :
113 0 : virtual ~CapabilitiesUpdater(){}
114 :
115 0 : virtual VisitorResult visit( Compound* compound )
116 : {
117 0 : const Channel* dest = compound->getInheritChannel();
118 0 : if( !dest || dest->getView() != _view )
119 0 : return TRAVERSE_CONTINUE;
120 :
121 0 : const Channel* src = compound->getChannel();
122 0 : if( !src->supportsView( _view ))
123 0 : return TRAVERSE_CONTINUE;
124 :
125 0 : const uint64_t supported = src->getCapabilities();
126 0 : _capabilities &= supported;
127 0 : return TRAVERSE_CONTINUE;
128 : }
129 :
130 0 : uint64_t getCapabilities() const { return _capabilities; }
131 :
132 : private:
133 : View* const _view;
134 : uint64_t _capabilities;
135 : };
136 :
137 0 : class UseEqualizerVisitor : public ConfigVisitor
138 : {
139 : public:
140 0 : UseEqualizerVisitor( const View* view ) : _view( view ) {}
141 :
142 : // No need to go down on nodes.
143 0 : VisitorResult visitPre( Node* ) override { return TRAVERSE_PRUNE; }
144 :
145 0 : VisitorResult visit( Compound* compound ) override
146 : {
147 0 : const Channel* dest = compound->getInheritChannel();
148 0 : if( !dest )
149 0 : return TRAVERSE_CONTINUE;
150 :
151 0 : if( dest->getView() != _view )
152 0 : return TRAVERSE_PRUNE;
153 :
154 0 : Equalizers equalizers = compound->getEqualizers();
155 0 : for( EqualizersCIter i = equalizers.begin(); i != equalizers.end(); ++i)
156 : {
157 0 : Equalizer* equalizer = *i;
158 0 : const uint32_t bitmask = _view->getEqualizers();
159 0 : equalizer->setActive( ( equalizer->getType() & bitmask ) != 0 );
160 : }
161 0 : return TRAVERSE_CONTINUE;
162 : }
163 :
164 :
165 : private:
166 : const View* const _view;
167 : };
168 :
169 0 : class UpdateEqualizersVisitor : public ConfigVisitor
170 : {
171 : public:
172 :
173 0 : UpdateEqualizersVisitor( const View* view ) : _view( view ) {}
174 :
175 : // No need to go down on nodes.
176 0 : VisitorResult visitPre( Node* ) override { return TRAVERSE_PRUNE; }
177 :
178 0 : VisitorResult visit( Compound* compound ) override
179 : {
180 0 : const Channel* dest = compound->getInheritChannel();
181 0 : if( !dest )
182 0 : return TRAVERSE_CONTINUE;
183 :
184 0 : if( dest->getView() != _view )
185 0 : return TRAVERSE_PRUNE;
186 :
187 0 : const TileQueues& queues = compound->getOutputTileQueues();
188 0 : for( TileQueuesCIter i = queues.begin(); i != queues.end(); ++i )
189 : {
190 0 : TileQueue* queue = *i;
191 0 : queue->setTileSize( _view->getEqualizer().getTileSize( ));
192 : }
193 :
194 0 : Equalizers equalizers = compound->getEqualizers();
195 0 : for( EqualizersIter i = equalizers.begin(); i != equalizers.end(); ++i)
196 0 : *(*i) = _view->getEqualizer();
197 :
198 0 : return TRAVERSE_CONTINUE;
199 : }
200 :
201 : private:
202 : const View* const _view;
203 : };
204 :
205 : }
206 :
207 850 : void View::setDirty( const uint64_t bits )
208 : {
209 850 : if( bits == 0 || !isAttached( ))
210 1587 : return;
211 :
212 113 : Super::setDirty( bits );
213 113 : _updateChannels();
214 : }
215 :
216 176 : void View::_updateChannels() const
217 : {
218 176 : LBASSERT( isMaster( ));
219 176 : co::ObjectVersion version( this );
220 176 : if( isDirty( ))
221 113 : ++version.version;
222 :
223 1056 : for( Channels::const_iterator i = _channels.begin();
224 704 : i != _channels.end(); ++i )
225 : {
226 176 : Channel* channel = *i;
227 176 : channel->setViewVersion( version );
228 : }
229 176 : }
230 :
231 8 : void View::deserialize( co::DataIStream& is, const uint64_t dirtyBits )
232 : {
233 8 : LBASSERT( isMaster( ));
234 8 : Super::deserialize( is, dirtyBits );
235 :
236 8 : if( dirtyBits & ( DIRTY_FRUSTUM | DIRTY_OVERDRAW | DIRTY_MODELUNIT ))
237 0 : updateFrusta();
238 8 : if( dirtyBits & DIRTY_EQUALIZER )
239 : {
240 0 : UpdateEqualizersVisitor visitor ( this );
241 0 : getConfig()->accept( visitor );
242 : }
243 8 : if( dirtyBits & DIRTY_EQUALIZERS )
244 : {
245 0 : UseEqualizerVisitor visitor ( this );
246 0 : getConfig()->accept( visitor );
247 0 : getConfig()->postNeedsFinish(); // @bug? Why?
248 : }
249 8 : }
250 :
251 523 : Config* View::getConfig()
252 : {
253 523 : Layout* layout = getLayout();
254 523 : LBASSERT( layout );
255 523 : return layout ? layout->getConfig() : 0;
256 : }
257 :
258 0 : const Config* View::getConfig() const
259 : {
260 0 : const Layout* layout = getLayout();
261 0 : LBASSERT( layout );
262 0 : return layout ? layout->getConfig() : 0;
263 : }
264 :
265 63 : ServerPtr View::getServer()
266 : {
267 63 : Config* config = getConfig();
268 63 : LBASSERT( config );
269 63 : return config ? config->getServer() : 0;
270 : }
271 :
272 636 : void View::addChannel( Channel* channel )
273 : {
274 636 : _channels.push_back( channel );
275 636 : }
276 :
277 635 : bool View::removeChannel( Channel* channel )
278 : {
279 635 : Channels::iterator i = lunchbox::find( _channels, channel );
280 :
281 635 : LBASSERT( i != _channels.end( ));
282 635 : if( i == _channels.end( ))
283 0 : return false;
284 :
285 635 : _channels.erase( i );
286 635 : return true;
287 : }
288 :
289 413 : ViewPath View::getPath() const
290 : {
291 413 : const Layout* layout = getLayout();
292 413 : LBASSERT( layout );
293 413 : ViewPath path( layout->getPath( ));
294 :
295 413 : const Views& views = layout->getViews();
296 413 : Views::const_iterator i = std::find( views.begin(), views.end(), this );
297 413 : LBASSERT( i != views.end( ));
298 413 : path.viewIndex = std::distance( views.begin(), i );
299 413 : return path;
300 : }
301 :
302 16 : void View::trigger( const Canvas* canvas, const bool active )
303 : {
304 16 : const Mode mode = getMode();
305 16 : Config* config = getConfig();
306 :
307 : // (De)activate destination compounds for canvas/eye(s)
308 96 : for( Channels::const_iterator i = _channels.begin();
309 64 : i != _channels.end(); ++i )
310 : {
311 16 : Channel* channel = *i;
312 16 : const Canvas* channelCanvas = channel->getCanvas();
313 16 : const Layout* canvasLayout = channelCanvas->getActiveLayout();
314 :
315 16 : if(( canvas && channelCanvas != canvas ) ||
316 0 : ( !canvas && canvasLayout != getLayout( )))
317 : {
318 0 : continue;
319 : }
320 :
321 16 : const Segment* segment = channel->getSegment();
322 16 : const uint32_t segmentEyes = segment->getEyes();
323 : const uint32_t eyes = ( mode == MODE_MONO ) ?
324 16 : EYE_CYCLOP & segmentEyes : EYES_STEREO & segmentEyes;
325 16 : if( eyes == 0 )
326 0 : continue;
327 :
328 16 : ConfigDestCompoundVisitor visitor( channel, true /*activeOnly*/ );
329 16 : config->accept( visitor );
330 :
331 16 : const Compounds& compounds = visitor.getResult();
332 96 : for( Compounds::const_iterator j = compounds.begin();
333 64 : j != compounds.end(); ++j )
334 : {
335 16 : Compound* compound = *j;
336 16 : if( active )
337 : {
338 8 : compound->activate( eyes );
339 8 : LBLOG( LOG_VIEW ) << "Activate " << compound->getName()
340 8 : << std::endl;
341 : }
342 : else
343 : {
344 8 : compound->deactivate( eyes );
345 8 : LBLOG( LOG_VIEW ) << "Deactivate " << compound->getName()
346 8 : << std::endl;
347 : }
348 : }
349 16 : }
350 16 : }
351 :
352 0 : void View::activateMode( const Mode mode )
353 : {
354 0 : if( getMode() == mode )
355 0 : return;
356 :
357 0 : Config* config = getConfig();
358 0 : if( config->isRunning( ))
359 : {
360 0 : config->postNeedsFinish();
361 0 : trigger( 0, false );
362 : }
363 :
364 0 : Super::activateMode( mode );
365 :
366 0 : if( config->isRunning( ))
367 0 : trigger( 0, true );
368 : }
369 :
370 0 : void View::updateCapabilities()
371 : {
372 0 : CapabilitiesUpdater visitor( this );
373 0 : getConfig()->accept( visitor );
374 0 : setCapabilities( visitor.getCapabilities( ));
375 0 : }
376 :
377 368 : void View::updateFrusta()
378 : {
379 368 : const Channels& channels = getChannels();
380 368 : Vector3f eye;
381 368 : const float ratio = _computeFocusRatio( eye );
382 :
383 368 : Config* config = getConfig();
384 368 : FrustumUpdater updater( channels, eye, ratio );
385 :
386 368 : config->accept( updater );
387 368 : }
388 :
389 368 : float View::_computeFocusRatio( Vector3f& eye )
390 : {
391 368 : eye = Vector3f::ZERO;
392 368 : const Observer* observer = getObserver();
393 368 : const FocusMode mode = observer ? observer->getFocusMode() :FOCUSMODE_FIXED;
394 368 : if( mode == FOCUSMODE_FIXED )
395 368 : return 1.f;
396 :
397 0 : const Channels& channels = getChannels();
398 0 : if( channels.empty( ))
399 0 : return 1.f;
400 :
401 0 : Vector4f view4( Vector3f::FORWARD );
402 0 : if( mode == FOCUSMODE_RELATIVE_TO_OBSERVER )
403 : {
404 0 : view4 = observer->getHeadMatrix() * view4;
405 0 : eye = observer->getEyeWorld( EYE_CYCLOP );
406 : }
407 0 : Vector3f view = view4;
408 0 : view.normalize();
409 :
410 0 : float distance = std::numeric_limits< float >::max();
411 0 : if( getCurrentType() != Frustum::TYPE_NONE ) // frustum from view
412 : {
413 0 : const Wall& wall = getWall();
414 0 : const Vector3f w = wall.getW();
415 0 : const float denom = view.dot( w );
416 0 : if( denom != 0.f ) // view parallel to wall
417 : {
418 0 : const float d = (wall.bottomLeft - eye).dot( w ) / denom;
419 0 : if( d > 0.f )
420 0 : distance = d;
421 : }
422 : }
423 : else
424 : {
425 : // Find closest segment and its distance from cyclop eye
426 0 : for( ChannelsCIter i = channels.begin(); i != channels.end(); ++i )
427 : {
428 0 : Segment* segment = (*i)->getSegment();
429 0 : segment->inheritFrustum();
430 0 : if( segment->getCurrentType() == Frustum::TYPE_NONE )
431 0 : continue;
432 :
433 : // http://en.wikipedia.org/wiki/Line-plane_intersection
434 0 : const Wall& wall = segment->getWall();
435 0 : const Vector3f w = wall.getW();
436 0 : const float denom = view.dot( w );
437 0 : if( denom == 0.f ) // view parallel to wall
438 0 : continue;
439 :
440 0 : const float d = (wall.bottomLeft - eye).dot( w ) / denom;
441 0 : if( d > distance || d <= 0.f ) // further away or behind
442 0 : continue;
443 :
444 0 : distance = d;
445 : //LBINFO << "Eye " << eye << " is " << d << " from " << wall
446 : // << std::endl;
447 : }
448 : }
449 :
450 0 : float focusDistance = observer->getFocusDistance();
451 0 : if( mode == FOCUSMODE_RELATIVE_TO_ORIGIN )
452 : {
453 0 : eye = observer->getEyeWorld( EYE_CYCLOP );
454 :
455 0 : if( distance != std::numeric_limits< float >::max( ))
456 : {
457 0 : distance += eye.z();
458 0 : focusDistance += eye.z();
459 0 : if( fabsf( distance ) <= std::numeric_limits< float >::epsilon( ))
460 0 : distance = 2.f * std::numeric_limits< float >::epsilon();
461 : }
462 : }
463 :
464 0 : if( distance == std::numeric_limits< float >::max( ))
465 0 : return 1.f;
466 0 : return focusDistance / distance;
467 : }
468 :
469 : }
470 : }
471 :
472 : #include "../fabric/view.ipp"
473 :
474 : template class eq::fabric::View< eq::server::Layout, eq::server::View,
475 : eq::server::Observer >;
476 : /** @cond IGNORE */
477 : template std::ostream& eq::fabric::operator << ( std::ostream&,
478 : const eq::fabric::View< eq::server::Layout,
479 : eq::server::View,
480 27 : eq::server::Observer >& );
481 : /** @endcond */
|