Ticket #211: OSGMultiDisplayWindow.cpp

File OSGMultiDisplayWindow.cpp, 19.5 kB (added by rstanchak, 11 months ago)

support class for the tutorial file

Line 
1 /*---------------------------------------------------------------------------*\
2  *                                OpenSG                                     *
3  *                                                                           *
4  *                                                                           *
5  *             Copyright (C) 2000-2002 by the OpenSG Forum                   *
6  *                                                                           *
7  *                            www.opensg.org                                 *
8  *                                                                           *
9  *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
10  *                                                                           *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13  *                                License                                    *
14  *                                                                           *
15  * This library is free software; you can redistribute it and/or modify it   *
16  * under the terms of the GNU Library General Public License as published    *
17  * by the Free Software Foundation, version 2.                               *
18  *                                                                           *
19  * This library is distributed in the hope that it will be useful, but       *
20  * WITHOUT ANY WARRANTY; without even the implied warranty of                *
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
22  * Library General Public License for more details.                          *
23  *                                                                           *
24  * You should have received a copy of the GNU Library General Public         *
25  * License along with this library; if not, write to the Free Software       *
26  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
27  *                                                                           *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30  *                                Changes                                    *
31  *                                                                           *
32  *                                                                           *
33  *                                                                           *
34  *                                                                           *
35  *                                                                           *
36  *                                                                           *
37 \*---------------------------------------------------------------------------*/
38
39 //---------------------------------------------------------------------------
40 //  Includes
41 //---------------------------------------------------------------------------
42
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <OSGConfig.h>
46 #include <OSGGL.h>
47 #include <OSGNodePtr.h>
48 #include <OSGViewport.h>
49 #include <OSGFBOViewport.h>
50 #include <OSGTileCameraDecorator.h>
51 #include <OSGBaseFunctions.h>
52 #include <OSGStereoBufferViewport.h>
53 #include <OSGFieldContainerFields.h>
54 #include <OSGDisplayFilterForeground.h>
55 #include <OSGRemoteAspect.h>
56 #include "OSGMultiDisplayWindow.h"
57 #include "OSGConnection.h"
58 #include "OSGNode.h"
59
60 #define FAST_SYNC 0
61
62 OSG_USING_NAMESPACE
63
64 /*! \class osg::MultiDisplayWindow
65  *  \ingroup GrpSystemCluster
66  */
67
68 /*----------------------- constructors & destructors ----------------------*/
69
70 /*! Constructor
71  */
72 MultiDisplayWindow::MultiDisplayWindow(void) :
73     Inherited()
74 {
75 }
76
77 /*! Copy Constructor
78  */
79 MultiDisplayWindow::MultiDisplayWindow(const MultiDisplayWindow &source) :
80     Inherited(source)
81 {
82 }
83
84 /*! Destructor
85  */
86 MultiDisplayWindow::~MultiDisplayWindow(void)
87 {
88 }
89
90 /*----------------------------- class specific ----------------------------*/
91
92 /*! initialize the static features of the class, e.g. action callbacks
93  */
94 void MultiDisplayWindow::initMethod (void)
95 {
96 }
97
98 /*! react to field changes
99  */
100 void MultiDisplayWindow::changed(BitVector whichField, UInt32 origin)
101 {
102     Inherited::changed(whichField, origin);
103 }
104
105 /*! output the instance for debug purposes
106  */
107 void MultiDisplayWindow::dump(      UInt32    ,
108                               const BitVector ) const
109 {
110     SLOG << "hServers:" << getHServers() << " "
111          << "vServers:" << getVServers() << std::endl;
112 }
113
114 /*----------------------------- server methods ----------------------------*/
115
116 /*! initialise the cluster window on the server side. This method is
117      called after the first sync.
118  */
119 void MultiDisplayWindow::serverInit( WindowPtr ,
120                                      UInt32 )
121 {
122 }
123
124 /*! render server window
125  * 
126  *  update all viewport parameters and render local viewports
127  *  Width and height of the whole window are calculated by
128  *  multiplieing the local window size by hServers and vServers.
129  */
130 void MultiDisplayWindow::serverRender( WindowPtr serverWindow,
131                                        UInt32 id,
132                                        RenderActionBase *action )
133 {
134     TileCameraDecoratorPtr deco;
135     ViewportPtr serverPort;
136     ViewportPtr clientPort;
137     StereoBufferViewportPtr clientStereoPort;
138     UInt32 sv,cv;
139     Int32 l,r,t,b;
140     Int32 cleft,cright,ctop,cbottom;
141
142         // sync, otherwise viewports will be out of date
143         
144
145     if(!getHServers())
146     {
147         setHServers(getServers().size());
148     }
149     if(!getVServers())
150     {
151         setVServers(1);
152     }
153     UInt32 row   =id/getHServers();
154     UInt32 column=id%getHServers();
155     // calculate width and height from local width and height
156     UInt32 width  = serverWindow->getWidth() ;
157     UInt32 height = serverWindow->getHeight();
158     if(getWidth()==0)
159     {
160         setWidth( width*getHServers() );
161     }
162     if(getHeight()==0)
163     {
164         setHeight( height*getVServers() );
165     }
166     Int32 left   = column * width  - column * getXOverlap();
167     Int32 bottom = row    * height - row    * getYOverlap();
168     Int32 right  = left   + width  - 1;
169     Int32 top    = bottom + height - 1;
170     Real64 scaleCWidth  = ((width - getXOverlap()) * (getHServers() - 1) + width) / (float)getWidth();
171     Real64 scaleCHeight = ((height - getYOverlap())* (getVServers() - 1) + height)/ (float)getHeight();
172         bool isVirtualPort=false;
173
174     // duplicate viewports
175     for(cv=0,sv=0;cv<getPort().size();cv++)
176     {
177         clientPort = getPort()[cv];
178                 isVirtualPort = clientPort->getType().isDerivedFrom(FBOViewport::getClassType());
179                 if(isVirtualPort){
180                         // TODO -- seems wrong to render this on all servers, though rendering
181                         // then transmitting the texture doesn't seem like a good idea either.
182                         if(serverWindow->getPort().size() <= sv)
183             {
184                 serverPort = ViewportPtr::dcast(clientPort->shallowCopy());
185                 beginEditCP(serverWindow);
186                 serverWindow->addPort(serverPort);
187                 endEditCP(serverWindow);
188             }
189                         else
190                         {
191                 serverPort = serverWindow->getPort()[sv];
192                 if(serverWindow->getPort()[sv]->getType() !=
193                         clientPort->getType())
194                 {
195                     // there is a viewport with the wrong type
196                     subRefCP(serverWindow->getPort()[sv]);
197                     serverPort = ViewportPtr::dcast(clientPort->shallowCopy());
198                     beginEditCP(serverWindow);
199                                         {
200                         serverWindow->getPort()[sv] = serverPort;
201                                         }
202                     endEditCP(serverWindow);
203                 }
204                         }
205                         // update changed viewport fields
206                         updateViewport(serverPort,clientPort);
207                 }
208                 else{
209                         clientStereoPort = StereoBufferViewportPtr::dcast(clientPort);
210                         cleft   = (Int32)(clientPort->getPixelLeft()      * scaleCWidth)   ;
211                         cbottom = (Int32)(clientPort->getPixelBottom()    * scaleCHeight)  ;
212                         cright  = (Int32)((clientPort->getPixelRight()+1) * scaleCWidth) -1;
213                         ctop    = (Int32)((clientPort->getPixelTop()+1)   * scaleCHeight)-1;
214
215                         if( cright  < left   ||
216                                         cleft   > right  ||
217                                         ctop    < bottom ||
218                                         cbottom > top       )
219                         {
220                                 // invisible on this server screen
221                                 continue;
222                         }
223                         // calculate overlapping viewport
224                         l = osgMax(cleft  ,left  ) - left;
225                         b = osgMax(cbottom,bottom) - bottom;
226                         r = osgMin(cright ,right ) - left;
227                         t = osgMin(ctop   ,top   ) - bottom;
228                         if(serverWindow->getPort().size() <= sv)
229                         {
230                                 serverPort = ViewportPtr::dcast(clientPort->shallowCopy());
231                                 beginEditCP(serverPort);
232                                 deco=TileCameraDecorator::create();
233                                 beginEditCP(serverWindow);
234                                 serverWindow->addPort(serverPort);
235                                 serverPort->setCamera(deco);
236                                 endEditCP(serverWindow);
237                                 endEditCP(serverPort);
238                         }
239                         else
240                         {
241                                 serverPort = serverWindow->getPort()[sv];
242                                 deco=TileCameraDecoratorPtr::dcast(serverPort->getCamera());
243                                 if(serverWindow->getPort()[sv]->getType() !=
244                                                 clientPort->getType())
245                                 {
246                                         // there is a viewport with the wrong type
247                                         subRefCP(serverWindow->getPort()[sv]);
248                                         serverPort = ViewportPtr::dcast(clientPort->shallowCopy());
249                                         beginEditCP(serverWindow);
250                                         serverWindow->getPort()[sv] = serverPort;
251                                         serverPort->setCamera(deco);
252                                         endEditCP(serverWindow);
253                                 }
254                                 else
255                                 {
256                                         deco=TileCameraDecoratorPtr::dcast(serverPort->getCamera());
257                                 }
258                         }
259
260                         // update changed viewport fields
261                         updateViewport(serverPort,clientPort);
262
263                 // set viewport size
264                 beginEditCP(serverPort,
265                             Viewport::LeftFieldMask|
266                             Viewport::BottomFieldMask|
267                             Viewport::RightFieldMask|
268                             Viewport::TopFieldMask);
269                 serverPort->setSize(Real32(l),Real32(b),Real32(r),Real32(t));
270                 // use pixel even if pixel = 1
271                         if(serverPort->getLeft() == 1.0)
272                                 serverPort->setLeft(1.0001);
273                         if(serverPort->getRight() == 1.0)
274                                 serverPort->setRight(1.0001);
275                         if(serverPort->getTop() == 1.0)
276                                 serverPort->setTop(1.0001);
277                         if(serverPort->getBottom() == 1.0)
278                                 serverPort->setBottom(1.0001);
279                         endEditCP(serverPort,
280                                         Viewport::LeftFieldMask|
281                                         Viewport::BottomFieldMask|
282                                         Viewport::RightFieldMask|
283                   Viewport::TopFieldMask);
284                         // calculate tile parameters
285                         beginEditCP(deco);
286                         deco->setFullWidth ( cright-cleft );
287                         deco->setFullHeight( ctop-cbottom );
288                         deco->setSize( ( l+left-cleft     ) / (float)( cright-cleft ),
289                        ( b+bottom-cbottom ) / (float)( ctop-cbottom ),
290                        ( r+left-cleft     ) / (float)( cright-cleft ),
291                        ( t+bottom-cbottom ) / (float)( ctop-cbottom ) );
292                         deco->setDecoratee( clientPort->getCamera() );
293                         endEditCP(deco);
294                 }
295         sv++;
296     }
297     // remove unused ports
298     while(serverWindow->getPort().size()>sv)
299     {
300         serverWindow->subPort(sv);
301     }
302     Inherited::serverRender(serverWindow,id,action);
303 }
304
305 /*! swap server window
306  */
307 void MultiDisplayWindow::serverSwap( WindowPtr window,UInt32 id )
308 {
309     Connection *connection;
310    
311     // clear command buffers
312     UInt8 pixel[3];
313     glReadPixels(0,0,
314                  1,1,
315                  GL_RGB,GL_UNSIGNED_BYTE,
316                  pixel);
317     glFinish();
318
319 #if !FAST_SYNC
320     connection=getNetwork()->getMainConnection();
321     if(!getInterleave())
322     {
323         // tell client that we are finish
324         connection->signal();
325         // wait for swap
326         connection->wait();
327     }
328 #endif
329     Inherited::serverSwap(window,id);
330 }
331
332 /*----------------------------- client methods ----------------------------*/
333
334 /*! init client window
335  * 
336  *  If manageClientViewports is set, then all viewports from the
337  *  cluster window are duplcated to the client window.
338  */
339 void MultiDisplayWindow::clientInit( void )
340 {
341     bool             changed = false;
342     ViewportPtr      vp,cvp;
343
344     if(getManageClientViewports() == false ||
345        getClientWindow() == NullFC)
346         return;
347
348     // check if something changed
349     if(getPort().size() == getClientWindow()->getPort().size())
350     {
351         for(UInt32 v = 0 ; v < getPort().size() && !changed ; v++)
352         {
353             vp  = getPort(v);
354             cvp = getClientWindow()->getPort(v);
355             if( vp->getRoot() != cvp->getRoot() ||
356                 vp->getLeft() != cvp->getLeft() ||
357                 vp->getRight() != cvp->getRight() ||
358                 vp->getBottom() != cvp->getBottom() ||
359                 vp->getTop() != cvp->getTop() ||
360                 vp->getBackground() != cvp->getBackground() ||
361                 vp->getForegrounds().size() != cvp->getForegrounds().size() )
362                 changed = true;
363         }
364     }
365     else
366     {
367         changed = true;
368     }
369
370     if(changed)
371     {
372         beginEditCP(getClientWindow());
373         // remove all viewports
374         while(getClientWindow()->getPort().size())
375         {
376             vp = getClientWindow()->getPort(0);
377             getClientWindow()->subPort(0);
378             subRefCP(vp);
379         }
380         // duplicate viewports
381         for(UInt32 v=0 ; v<getPort().size() ;v++)
382         {
383             getClientWindow()->addPort(ViewportPtr::dcast(getPort(v)->shallowCopy()));
384         }
385         endEditCP(getClientWindow());
386     }
387 }
388    
389 /*! render client window
390  */
391 void MultiDisplayWindow::clientSwap( void )
392 {
393     Connection *connection=getNetwork()->getMainConnection();
394
395 #if FAST_SYNC
396     connection->selectChannel();
397 #else
398     if(!getInterleave())
399     {
400         // wait for all servers to finish
401         connection->wait();
402         // initiate swap
403         connection->signal();
404     }
405 #endif
406
407     // show client window
408     Inherited::clientSwap();
409 }
410
411 /*-------------------------------------------------------------------------*/
412 /*                              helper                                     */
413
414 /*! update all changed viewport field from the client port
415  */
416 class RemoteAspectAccess : public RemoteAspect
417 {
418 public:
419     static BitVector getFieldFilter(UInt32 id){
420         return RemoteAspect::_fieldFilter[id];
421     }
422 };
423
424 void MultiDisplayWindow::updateViewport(ViewportPtr &serverPort,
425                                         ViewportPtr &clientPort)
426 {
427     bool equal, found;
428
429     // Compare the pointers.
430     if(serverPort == clientPort)
431         return;
432     if(serverPort == NullFC || clientPort == NullFC)
433         return;
434     if(serverPort->getType() != serverPort->getType())
435         return;
436    
437     const FieldContainerType &type = serverPort->getType();
438     UInt32 fcount = osgMin(serverPort->getType().getNumFieldDescs(),
439                            clientPort->getType().getNumFieldDescs());
440    
441         BitVector ffilter = RemoteAspectAccess::getFieldFilter( type.getId() );
442     for(UInt32 i=1;i <= fcount;++i)
443     {
444         const FieldDescription* fdesc = type.getFieldDescription(i);
445         // ignore attachments
446         if(strcmp(fdesc->getCName(), "parent") == 0 ||
447            strcmp(fdesc->getCName(), "camera") == 0)
448             continue;
449
450         BitVector mask = fdesc->getFieldMask();
451
452                 // don't update filtered fields
453                 //std::cout<<"Filter field "<<fdesc->getCName()<<": "<<(((UInt32) ffilter & mask)!=0)<<std::endl;
454                 if(ffilter & mask) continue;
455
456         Field *dst_field = serverPort->getField(i);
457         Field *src_field = clientPort->getField(i);
458    
459         const FieldType &dst_ftype = dst_field->getType();
460         const FieldType &src_ftype = src_field->getType();
461
462         if(dst_ftype != src_ftype)
463             continue;
464    
465         equal = true;
466         found = false;
467
468         if(strstr(dst_ftype.getCName(), "Ptr") == NULL)
469         {
470             // This is very slow with multi fields!!!!
471             std::string av, bv;
472             dst_field->getValueByStr(av);
473             src_field->getValueByStr(bv);
474             if(av != bv)
475                 equal = false;
476         }
477         else
478         {
479             if(dst_field->getCardinality() == FieldType::SINGLE_FIELD)
480             {
481                 if((((SFFieldContainerPtr *)dst_field)->getValue() !=
482                     ((SFFieldContainerPtr *)src_field)->getValue()))
483                     equal = false;
484             }
485             else if(dst_field->getCardinality() == FieldType::MULTI_FIELD)
486             {
487                 UInt32 j, cn = ((MFFieldContainerPtr*)src_field)->size(),
488                           sn = ((MFFieldContainerPtr*)src_field)->size();
489                          
490                 if (strcmp(fdesc->getCName(), "foregrounds") == 0)
491                 {
492                     MFForegroundPtr sFgndBag;
493                     MFForegroundPtr::iterator sFgndIt, cFgndIt;
494                     DisplayFilterForegroundPtr filterFgnd = NullFC;
495                    
496                     sFgndIt = serverPort->getForegrounds().begin();
497                     cFgndIt = clientPort->getForegrounds().begin();
498                    
499                     while (sFgndIt != serverPort->getForegrounds().end())
500                     {
501                         filterFgnd = DisplayFilterForegroundPtr::dcast(*sFgndIt);
502                        
503                         if (filterFgnd != NullFC &&
504                            !filterFgnd->getServer().empty())
505                             found = true;   // loaded filters found
506                         else
507                             sFgndBag.push_back(*sFgndIt);
508                            
509                         ++sFgndIt;
510                     }
511                    
512                     if (sFgndBag.size() != clientPort->getForegrounds().size())
513                     {
514                         equal = false;
515                     }
516                     else
517                     {
518                         sFgndIt = sFgndBag.begin();
519                        
520                         while (sFgndIt != sFgndBag.end() &&
521                                cFgndIt != clientPort->getForegrounds().end() &&
522                               *sFgndIt == *cFgndIt)
523                         {
524                             ++sFgndIt;
525                             ++cFgndIt;
526                         }
527                        
528                         if (sFgndIt != sFgndBag.end() ||
529                             cFgndIt != clientPort->getForegrounds().end())
530                             equal = false;
531                     }
532                 }
533                 else
534                 {
535                     if(((MFFieldContainerPtr*)dst_field)->size() !=
536                     ((MFFieldContainerPtr*)src_field)->size()) {
537                         equal = false;
538                     }
539                     else {
540                         for(j=0;j < ((MFFieldContainerPtr*)dst_field)->size();++j)
541                         {
542                             if(((*(((MFFieldContainerPtr *)dst_field)))[j] !=
543                                 (*(((MFFieldContainerPtr *)src_field)))[j]))
544                                 equal = false;
545                         }
546                     }
547                 }
548             }
549         }
550         if(equal == false)
551         {
552             beginEditCP(serverPort, mask);
553             dst_field->setAbstrValue(*src_field);
554             endEditCP(serverPort, mask);
555            
556             if (found)
557             {
558                 ClusterWindowPtr ptr(this);
559        
560                 beginEditCP(ptr, DirtyFieldMask);
561                     setDirty(true);
562                 endEditCP(ptr, DirtyFieldMask);
563             }
564         }
565     }
566 }
567
568 /*-------------------------------------------------------------------------*/
569 /*                              cvs id's                                   */
570
571 #ifdef __sgi
572 #pragma set woff 1174
573 #endif
574
575 #ifdef OSG_LINUX_ICC
576 #pragma warning( disable : 177 )
577 #endif
578
579 namespace
580 {
581     static char cvsid_cpp[] = "@(#)$Id: $";
582     static char cvsid_hpp[] = OSGMULTIDISPLAYCONFIG_HEADER_CVSID;
583     static char cvsid_inl[] = OSGMULTIDISPLAYCONFIG_INLINE_CVSID;
584 }