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