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(ShadowVolumeGen *shadowgen, unsigned int camera, Mode rendermode)
00033 {
00034     //RenderWalk((SceneNode*)m_Root,0);
00035 
00036     glGetFloatv(GL_MODELVIEW_MATRIX,m_TopTransform.arr());  
00037 
00038     unsigned int cameracode = 1<<camera;
00039 
00040     // render all the children of the root
00041     for (vector<Node*>::iterator i=m_Root->Children.begin(); i!=m_Root->Children.end(); ++i)
00042     {
00043         RenderWalk((SceneNode*)*i,0,cameracode,shadowgen,rendermode);
00044     }
00045     
00046     // now render the depth sorted primitives:
00047     m_DepthSorter.Render();
00048     m_DepthSorter.Clear();
00049 }
00050 
00051 void SceneGraph::RenderWalk(SceneNode *node,  int depth, unsigned int cameracode, ShadowVolumeGen *shadowgen, Mode rendermode)
00052 {
00053     // max gl matrix stack is 32 
00054     /*if (depth>=30)
00055     {
00056         Trace::Stream<<"SceneGraph::RenderWalk: max stack reached"<<endl;
00057         return;
00058     }*/
00059     
00060     if ((node->Prim->GetVisibility()&cameracode)==0) return;
00061     if (rendermode==SELECT && !node->Prim->IsSelectable()) return;
00062 
00063     dMatrix parent;
00064     // see if we need the parent (result of all the parents) transform
00065     if (node->Prim->GetState()->Hints & HINT_DEPTH_SORT)
00066     {
00067         glGetFloatv(GL_MODELVIEW_MATRIX,parent.arr());
00068     }
00069     
00070     glPushMatrix();     
00071     
00072     // if we are a lazy parent then we need to ignore 
00073     // the effects of the heirachical transform - we 
00074     // treat their transform as a world space one
00075     if (node->Prim->GetState()->Hints & HINT_LAZY_PARENT)
00076     {
00077         glLoadMatrixf(m_TopTransform.arr());
00078     }
00079     
00080     node->Prim->ApplyState();
00081     
00083     //if (!FrustumClip(node))
00084     {
00085         if (node->Prim->GetState()->Hints & HINT_DEPTH_SORT)
00086         {
00087             // render it later, and after depth sorting
00088             m_DepthSorter.Add(parent,node->Prim,node->ID);
00089         }
00090         else
00091         {
00092             glPushName(node->ID);
00093             node->Prim->Prerender();
00094             node->Prim->Render();
00095             glPopName();
00096         }
00097 
00098         depth++;
00099 
00100         for (vector<Node*>::iterator i=node->Children.begin(); i!=node->Children.end(); ++i)
00101         {
00102             RenderWalk((SceneNode*)*i,depth,cameracode,shadowgen,rendermode);
00103         }
00104     }
00105     glPopMatrix();
00106     
00107     if (node->Prim->GetState()->Hints & HINT_CAST_SHADOW)
00108     {
00109         shadowgen->Generate(node->Prim);
00110     }
00111 }
00112 
00113 // this is working the wrong way - need to write proper 
00114 // frustum culling by building planes from the camera 
00115 // frustum and checking is any points are inside
00116 bool SceneGraph::FrustumClip(SceneNode *node)
00117 {
00118     // do the frustum clip
00119     dBoundingBox box; 
00120     GetBoundingBox(node,box);
00121     dMatrix mat,proj;
00122     glGetFloatv(GL_MODELVIEW_MATRIX,mat.arr());
00123     glGetFloatv(GL_PROJECTION_MATRIX,proj.arr());
00124     mat=proj*mat;
00125     char cs = 0xff;
00126     
00127     dVector p = mat.transform_persp(box.min);
00128     CohenSutherland(p,cs);
00129     p=mat.transform_persp(box.max);
00130     CohenSutherland(p,cs);
00131     p=mat.transform_persp(dVector(box.min.x,box.min.y,box.max.z));
00132     CohenSutherland(p,cs);
00133     p=mat.transform_persp(dVector(box.min.x,box.max.y,box.min.z));
00134     CohenSutherland(p,cs);
00135     p=mat.transform_persp(dVector(box.min.x,box.max.y,box.max.z));
00136     CohenSutherland(p,cs);
00137     p=mat.transform_persp(dVector(box.max.x,box.min.y,box.min.z));
00138     CohenSutherland(p,cs);
00139     p=mat.transform_persp(dVector(box.max.x,box.min.y,box.max.z));
00140     CohenSutherland(p,cs);
00141     p=mat.transform_persp(dVector(box.max.x,box.max.y,box.min.z));
00142     CohenSutherland(p,cs);
00143 
00144     return cs!=0;
00145 }
00146 
00147 void SceneGraph::CohenSutherland(const dVector &p, char &cs)
00148 {
00149     char t=0;
00150     if (p.z>0.0f) // in front of the camera
00151     {
00152         if (p.x>1)       t |= 0x01;
00153         else if (p.x<-1) t |= 0x02;
00154         if (p.y>1)       t |= 0x04;
00155         else if (p.y<-1) t |= 0x08;
00156     }
00157     else // behind the camera
00158     {
00159         if (p.x<-1)    t |= 0x01;
00160         else if (p.x>1) t |= 0x02;
00161         if (p.y<-1)     t |= 0x04;
00162         else if (p.y>1) t |= 0x08;
00163     }
00164     cs&=t;
00165 }
00166 
00167 void SceneGraph::Detach(SceneNode *node)
00168 {
00169     if (node->Parent!=m_Root)
00170     {
00171         // keep the concatenated transform
00172         node->Prim->GetState()->Transform=GetGlobalTransform(node);
00173         
00174         // move node to the root
00175         node->Parent->RemoveChild(node->ID);
00176         m_Root->Children.push_back(node);
00177         node->Parent=m_Root;
00178     }
00179 }
00180 
00181 dMatrix SceneGraph::GetGlobalTransform(const SceneNode *node) const
00182 {
00183     dMatrix Mat,Ret;
00184     
00185     list<const SceneNode*> Path;
00186     
00187     const SceneNode* current=node;
00188     
00189     // iterate back up the tree storing parents...
00190     // lazy parent objects are treated as non-heirachical,
00191     // so we can stop if we find one of them - and
00192     // use it's transform as world space
00193     bool foundlazy=false;
00194     while(current!=NULL && !foundlazy)
00195     {
00196         if (current && current->Prim) 
00197         {
00198             Path.push_front(current);
00199             foundlazy = current->Prim->GetState()->Hints & HINT_LAZY_PARENT;
00200         }
00201         current=(const SceneNode*)current->Parent;
00202     }
00203         
00204     // concatenate the matrices together to get the global
00205     for (list<const SceneNode*>::iterator i=Path.begin(); i!=Path.end(); ++i)
00206     {
00207         Mat*=(*i)->Prim->GetState()->Transform;
00208     }
00209 
00210     return Mat;
00211 }
00212 
00213 void SceneGraph::GetBoundingBox(SceneNode *node, dBoundingBox &result)
00214 {
00215     dMatrix mat;
00216     GetBoundingBox(node, mat, result);
00217 }
00218 
00219 void SceneGraph::GetBoundingBox(SceneNode *node, dMatrix mat, dBoundingBox &result)
00220 {
00221     if (!node) return;
00222     
00223     if (node->Prim)
00224     {
00225         dVector point(0,0,0);
00226         dBoundingBox bbox=node->Prim->GetBoundingBox();
00227         bbox.min=mat.transform(bbox.min);
00228         bbox.max=mat.transform(bbox.max);
00229         result.expand(bbox);
00230         mat*=node->Prim->GetState()->Transform;
00231     }
00232 
00233     for (vector<Node*>::iterator i=node->Children.begin(); i!=node->Children.end(); ++i)
00234     {
00235         GetBoundingBox((SceneNode*)*i,mat,result);
00236     }
00237 }
00238 
00239 void SceneGraph::GetNodes(const Node *node, vector<const SceneNode*> &nodes) const
00240 {       
00241     nodes.push_back(static_cast<const SceneNode*>(node));
00242     
00243     for (vector<Node*>::const_iterator i=node->Children.begin(); 
00244             i!=node->Children.end(); i++)
00245     {
00246         GetNodes(*i,nodes);
00247     }
00248 }
00249 
00250 void SceneGraph::GetConnections(const Node *node, vector<pair<const SceneNode*,const SceneNode*> > &connections) const
00251 {       
00252     for (vector<Node*>::const_iterator i=node->Children.begin(); 
00253             i!=node->Children.end(); i++)
00254     {
00255         connections.push_back(pair<const SceneNode *,const SceneNode *>
00256                                 (static_cast<const SceneNode*>(node),
00257                                  static_cast<const SceneNode*>(*i)));
00258         GetConnections(*i,connections);
00259     }
00260 }
00261 void SceneGraph::Clear()
00262 {
00263     Tree::Clear();
00264     SceneNode *root = new SceneNode(NULL);
00265     AddNode(0,root);
00266 }

Generated on Wed Sep 17 21:16:30 2008 for The Fluxus Renderer (libfluxus) by  doxygen 1.5.1