SceneGraph.cpp

Go to the documentation of this file.
00001 // Copyright (C) 2005 Dave Griffiths
00002 //
00003 // This program is free software; you can redistribute it and/or modify
00004 // it under the terms of the GNU General Public License as published by
00005 // the Free Software Foundation; either version 2 of the License, or
00006 // (at your option) any later version.
00007 //
00008 // This program is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 // GNU General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU General Public License
00014 // along with this program; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00016 
00017 #include "SceneGraph.h"
00018 #include "PolyPrimitive.h"
00019 
00020 using namespace Fluxus;
00021 
00022 SceneGraph::SceneGraph()
00023 {
00024     // need to reset to having a root node present
00025     Clear();
00026 }
00027 
00028 SceneGraph::~SceneGraph()
00029 {
00030 }
00031 
00032 void SceneGraph::Render(Mode rendermode)
00033 {
00034     //RenderWalk((SceneNode*)m_Root,0);
00035 
00036     glGetFloatv(GL_MODELVIEW_MATRIX,m_TopTransform.arr());  
00037 
00038     // render all the children of the root
00039     for (vector<Node*>::iterator i=m_Root->Children.begin(); i!=m_Root->Children.end(); ++i)
00040     {
00041         RenderWalk((SceneNode*)*i,0,rendermode);
00042     }
00043     
00044     // now render the depth sorted primitives:
00045     m_DepthSorter.Render();
00046     m_DepthSorter.Clear();
00047 }
00048 
00049 void SceneGraph::RenderWalk(SceneNode *node, int depth, Mode rendermode)
00050 {
00051     // max gl matrix stack is 32 
00052     /*if (depth>=30)
00053     {
00054         Trace::Stream<<"SceneGraph::RenderWalk: max stack reached"<<endl;
00055         return;
00056     }*/
00057     
00058     if (node->Prim->Hidden()) return;
00059     if (rendermode==SELECT && !node->Prim->IsSelectable()) return;
00060     
00061     
00062     dMatrix parent;
00063     // see if we need the parent (result of all the parents) transform
00064     if (node->Prim->GetState()->Hints & HINT_DEPTH_SORT)
00065     {
00066         glGetFloatv(GL_MODELVIEW_MATRIX,parent.arr());
00067     }
00068     
00069     glPushMatrix();     
00070     
00071     // if we are a lazy parent then we need to ignore 
00072     // the effects of the heirachical transform - we 
00073     // treat their transform as a world space one
00074     if (node->Prim->GetState()->Hints & HINT_LAZY_PARENT)
00075     {
00076         glLoadMatrixf(m_TopTransform.arr());
00077     }
00078     
00079     node->Prim->ApplyState();
00080     
00082     //if (!FrustumClip(node))
00083     {
00084         if (node->Prim->GetState()->Hints & HINT_DEPTH_SORT)
00085         {
00086             // render it later, and after depth sorting
00087             m_DepthSorter.Add(parent,node->Prim,node->ID);
00088         }
00089         else
00090         {
00091             glPushName(node->ID);
00092             node->Prim->Prerender();
00093             node->Prim->Render();
00094             glPopName();
00095         }
00096 
00097         depth++;
00098 
00099         for (vector<Node*>::iterator i=node->Children.begin(); i!=node->Children.end(); ++i)
00100         {
00101             RenderWalk((SceneNode*)*i,depth,rendermode);
00102         }
00103     }
00104     glPopMatrix();
00105     
00106     if (node->Prim->GetState()->Hints & HINT_CAST_SHADOW)
00107     {
00108         m_ShadowVolumeGen.Generate(node->Prim);
00109     }
00110 }
00111 
00112 // this is working the wrong way - need to write proper 
00113 // frustum culling by building planes from the camera 
00114 // frustum and checking is any points are inside
00115 bool SceneGraph::FrustumClip(SceneNode *node)
00116 {
00117     // do the frustum clip
00118     dBoundingBox box; 
00119     GetBoundingBox(node,box);
00120     dMatrix mat,proj;
00121     glGetFloatv(GL_MODELVIEW_MATRIX,mat.arr());
00122     glGetFloatv(GL_PROJECTION_MATRIX,proj.arr());
00123     mat=proj*mat;
00124     char cs = 0xff;
00125     
00126     dVector p = mat.transform_persp(box.min);
00127     CohenSutherland(p,cs);
00128     p=mat.transform_persp(box.max);
00129     CohenSutherland(p,cs);
00130     p=mat.transform_persp(dVector(box.min.x,box.min.y,box.max.z));
00131     CohenSutherland(p,cs);
00132     p=mat.transform_persp(dVector(box.min.x,box.max.y,box.min.z));
00133     CohenSutherland(p,cs);
00134     p=mat.transform_persp(dVector(box.min.x,box.max.y,box.max.z));
00135     CohenSutherland(p,cs);
00136     p=mat.transform_persp(dVector(box.max.x,box.min.y,box.min.z));
00137     CohenSutherland(p,cs);
00138     p=mat.transform_persp(dVector(box.max.x,box.min.y,box.max.z));
00139     CohenSutherland(p,cs);
00140     p=mat.transform_persp(dVector(box.max.x,box.max.y,box.min.z));
00141     CohenSutherland(p,cs);
00142 
00143     return cs!=0;
00144 }
00145 
00146 void SceneGraph::CohenSutherland(const dVector &p, char &cs)
00147 {
00148     char t=0;
00149     if (p.z>0.0f) // in front of the camera
00150     {
00151         if (p.x>1)       t |= 0x01;
00152         else if (p.x<-1) t |= 0x02;
00153         if (p.y>1)       t |= 0x04;
00154         else if (p.y<-1) t |= 0x08;
00155     }
00156     else // behind the camera
00157     {
00158         if (p.x<-1)    t |= 0x01;
00159         else if (p.x>1) t |= 0x02;
00160         if (p.y<-1)     t |= 0x04;
00161         else if (p.y>1) t |= 0x08;
00162     }
00163     cs&=t;
00164 }
00165 
00166 void SceneGraph::Detach(SceneNode *node)
00167 {
00168     if (node->Parent!=m_Root)
00169     {
00170         // keep the concatenated transform
00171         node->Prim->GetState()->Transform=GetGlobalTransform(node);
00172         
00173         // move node to the root
00174         node->Parent->RemoveChild(node->ID);
00175         m_Root->Children.push_back(node);
00176         node->Parent=m_Root;
00177     }
00178 }
00179 
00180 dMatrix SceneGraph::GetGlobalTransform(const SceneNode *node) const
00181 {
00182     dMatrix Mat,Ret;
00183     
00184     list<const SceneNode*> Path;
00185     
00186     const SceneNode* current=node;
00187     
00188     // iterate back up the tree storing parents...
00189     // lazy parent objects are treated as non-heirachical,
00190     // so we can stop if we find one of them - and
00191     // use it's transform as world space
00192     bool foundlazy=false;
00193     while(current!=NULL && !foundlazy)
00194     {
00195         if (current && current->Prim) 
00196         {
00197             Path.push_front(current);
00198             foundlazy = current->Prim->GetState()->Hints & HINT_LAZY_PARENT;
00199         }
00200         current=(const SceneNode*)current->Parent;
00201     }
00202         
00203     // concatenate the matrices together to get the global
00204     for (list<const SceneNode*>::iterator i=Path.begin(); i!=Path.end(); ++i)
00205     {
00206         Mat*=(*i)->Prim->GetState()->Transform;
00207     }
00208 
00209     return Mat;
00210 }
00211 
00212 void SceneGraph::GetBoundingBox(SceneNode *node, dBoundingBox &result)
00213 {
00214     dMatrix mat;
00215     GetBoundingBox(node, mat, result);
00216 }
00217 
00218 void SceneGraph::GetBoundingBox(SceneNode *node, dMatrix mat, dBoundingBox &result)
00219 {
00220     if (!node) return;
00221     
00222     if (node->Prim)
00223     {
00224         dVector point(0,0,0);
00225         dBoundingBox bbox=node->Prim->GetBoundingBox();
00226         bbox.min=mat.transform(bbox.min);
00227         bbox.max=mat.transform(bbox.max);
00228         result.expand(bbox);
00229         mat*=node->Prim->GetState()->Transform;
00230     }
00231 
00232     for (vector<Node*>::iterator i=node->Children.begin(); i!=node->Children.end(); ++i)
00233     {
00234         GetBoundingBox((SceneNode*)*i,mat,result);
00235     }
00236 }
00237 
00238 void SceneGraph::GetNodes(const Node *node, vector<const SceneNode*> &nodes) const
00239 {       
00240     nodes.push_back(static_cast<const SceneNode*>(node));
00241     
00242     for (vector<Node*>::const_iterator i=node->Children.begin(); 
00243             i!=node->Children.end(); i++)
00244     {
00245         GetNodes(*i,nodes);
00246     }
00247 }
00248 
00249 void SceneGraph::GetConnections(const Node *node, vector<pair<const SceneNode*,const SceneNode*> > &connections) const
00250 {       
00251     for (vector<Node*>::const_iterator i=node->Children.begin(); 
00252             i!=node->Children.end(); i++)
00253     {
00254         connections.push_back(pair<const SceneNode *,const SceneNode *>
00255                                 (static_cast<const SceneNode*>(node),
00256                                  static_cast<const SceneNode*>(*i)));
00257         GetConnections(*i,connections);
00258     }
00259 }
00260 void SceneGraph::Clear()
00261 {
00262     Tree::Clear();
00263     SceneNode *root = new SceneNode(NULL);
00264     AddNode(0,root);
00265 }

Generated on Tue Sep 4 23:22:18 2007 for The Fluxus Renderer (libfluxus) by  doxygen 1.5.1