Renderer.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 "Renderer.h"
00018 #include "State.h"
00019 #include "Primitive.h"
00020 #include "PNGLoader.h"
00021 #include "SearchPaths.h"
00022 #include "PrimitiveIO.h"
00023 #include "ShaderCache.h"
00024 #include "Trace.h"
00025 #include <sys/time.h>
00026 #include <stdio.h>
00027 #include <unistd.h>
00028 
00029 using namespace Fluxus;
00030 
00031 //#define DEBUG_TRACE
00032 
00033 // should use glew for this?
00034 #ifndef GL_POLYGON_OFFSET
00035 #define GL_POLYGON_OFFSET GL_POLYGON_OFFSET_EXT
00036 #endif
00037 
00038 static const int FRAMES_PER_TIME = 10;
00039 static int TimeCounter = 0;
00040 static timeval StartTime;
00041 static float FPS;
00042 
00043 static const int MAXLIGHTS = 8;
00044 
00045 Renderer::Renderer() :
00046 m_Initialised(false),
00047 m_InitLights(false),
00048 m_Width(640),
00049 m_Height(480),
00050 m_MotionBlur(false),
00051 m_Fade(0.02f),
00052 m_ShowAxis(false),
00053 m_Grabbed(NULL),
00054 m_ClearFrame(true),
00055 m_ClearZBuffer(true),
00056 m_ClearAccum(false),
00057 m_FogDensity(0), 
00058 m_FogStart(0),
00059 m_FogEnd(100),  
00060 m_ShadowLight(0),
00061 m_StereoMode(noStereo),
00062 m_MaskRed(true),
00063 m_MaskGreen(true),
00064 m_MaskBlue(true),
00065 m_MaskAlpha(true),
00066 m_Deadline(1/25.0f),
00067 m_FPSDisplay(false),
00068 m_Time(0),
00069 m_Delta(0)
00070 {
00071     Clear();
00072     
00073     // stop valgrind complaining
00074     m_LastTime.tv_sec=0;
00075     m_LastTime.tv_usec=0;
00076 }
00077 
00078 Renderer::~Renderer()
00079 {
00080     TexturePainter::Shutdown();
00081     SearchPaths::Shutdown();
00082 }
00083 
00085 
00086 void Renderer::Clear()
00087 {
00088     m_World.Clear();
00089     m_StateStack.clear();
00090     m_CameraVec.clear();
00091     UnGrab();
00092     State InitialState;
00093     m_StateStack.push_back(InitialState);
00094     
00095     // add the default camera
00096     Camera cam;
00097     m_CameraVec.push_back(cam);
00098 }   
00099 
00100 void Renderer::Render()
00101 {           
00102     
00104     if (m_ClearFrame && !m_MotionBlur)
00105     {
00106         glClearColor(m_BGColour.r,m_BGColour.g,m_BGColour.b,m_BGColour.a);  
00107         glClear(GL_COLOR_BUFFER_BIT);   
00108     }
00109     
00110     if (m_ClearZBuffer)
00111     {
00112         glClear(GL_DEPTH_BUFFER_BIT);
00113     }
00114 
00115     if (m_ClearAccum)
00116     {
00117         glClear(GL_ACCUM_BUFFER_BIT);
00118     }
00119     
00120     for (unsigned int cam=0; cam<m_CameraVec.size(); cam++)
00121     {
00122         // need to clear this even if we aren't using shadows
00123         m_ShadowVolumeGen.Clear();
00124         
00125         if (m_ShadowLight!=0)
00126         {       
00127             RenderStencilShadows(cam);
00128         }
00129         else
00130         {
00131             PreRender(cam);
00132             m_World.Render(&m_ShadowVolumeGen,cam);
00133             m_ImmediateMode.Render(cam);
00134             m_ImmediateMode.Clear();
00135             PostRender();
00136         }       
00137     }
00138         
00139     timeval ThisTime;
00140     // stop valgrind complaining
00141     ThisTime.tv_sec=0;
00142     ThisTime.tv_usec=0;
00143     
00144     gettimeofday(&ThisTime,NULL);
00145     m_Delta=(ThisTime.tv_sec-m_LastTime.tv_sec)+
00146             (ThisTime.tv_usec-m_LastTime.tv_usec)*0.000001f;
00147 
00148     if (m_Delta<m_Deadline)
00149     {
00150         //min 1 hz
00151         if(m_Deadline-m_Delta<1.0f)
00152         {
00153             usleep((int)((m_Deadline-m_Delta)*1000000.0f));
00154         }
00155     }
00156     
00157     m_LastTime=ThisTime;
00158     //if (m_Delta>0) m_Time=ThisTime.tv_sec+ThisTime.tv_usec*0.000001f;
00159     if (m_Delta>0.0f && m_Delta<100.0f) m_Time+=m_Delta;
00160 }
00161 
00162 void Renderer::RenderStencilShadows(unsigned int CamIndex)
00163 {
00164     if (m_LightVec.size()>m_ShadowLight)
00165     {
00166         m_ShadowVolumeGen.SetLightPosition(m_LightVec[m_ShadowLight]->GetPosition());
00167     }
00168     
00169     PreRender(CamIndex);
00170     glDisable(GL_LIGHT0+m_ShadowLight); 
00171     m_World.Render(&m_ShadowVolumeGen,CamIndex);
00172     m_ImmediateMode.Render(CamIndex,&m_ShadowVolumeGen);
00173 
00174     glClear(GL_STENCIL_BUFFER_BIT);
00175     glEnable(GL_STENCIL_TEST);
00176     glStencilFunc(GL_ALWAYS, 0, ~0);
00177     glEnable(GL_DEPTH_TEST);
00178     glDepthFunc(GL_LESS);
00179     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
00180     glDepthMask(GL_FALSE);
00181     glEnable(GL_CULL_FACE);
00182 
00183     glCullFace(GL_BACK);
00184     glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
00185     m_ShadowVolumeGen.GetVolume()->Render();
00186 
00187     glCullFace(GL_FRONT);
00188     glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
00189     m_ShadowVolumeGen.GetVolume()->Render();
00190 
00191     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00192     glDepthFunc(GL_EQUAL);
00193     glStencilFunc(GL_EQUAL, 0, ~0);
00194     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
00195 
00196     glEnable(GL_BLEND);
00197     glBlendFunc(GL_ONE, GL_ONE);
00198     glCullFace(GL_BACK);
00199 
00200     glEnable(GL_LIGHT0+m_ShadowLight);
00201 
00202     // todo - needlessly generating shadow geom again - move 
00203     // generator into renderer and pass in like immediate mode
00204     m_World.Render(&m_ShadowVolumeGen,CamIndex);
00205     m_ImmediateMode.Render(CamIndex);
00206     m_ImmediateMode.Clear();
00207 
00208     glDepthMask(GL_TRUE);
00209     glDepthFunc(GL_LEQUAL);
00210     glStencilFunc(GL_ALWAYS, 0, ~0);
00211 
00212     if (m_ShadowVolumeGen.GetDebug())
00213     {
00214         m_ShadowVolumeGen.GetVolume()->GetState()->Hints=HINT_WIRE;
00215         m_ShadowVolumeGen.GetVolume()->Render();
00216         m_ShadowVolumeGen.GetVolume()->GetState()->Hints=HINT_SOLID;
00217     }
00218 
00219     PostRender();
00220 }
00221 
00222 void Renderer::PreRender(unsigned int CamIndex, bool PickMode)
00223 {
00224     Camera &Cam = m_CameraVec[CamIndex];
00225     if (!m_Initialised || PickMode || Cam.NeedsInit())
00226     {
00227         glViewport((int)(Cam.GetViewportX()*(float)m_Width),(int)(Cam.GetViewportY()*(float)m_Height),
00228             (int)(Cam.GetViewportWidth()*(float)m_Width),(int)(Cam.GetViewportHeight()*(float)m_Height));
00229         
00230         glMatrixMode (GL_PROJECTION);
00231         glLoadIdentity();
00232         
00233         if (PickMode) 
00234         {       
00235             GLint viewport[4]={0,0,m_Width,m_Height};
00236             gluPickMatrix(m_SelectInfo.x,m_Height-m_SelectInfo.y,
00237                         m_SelectInfo.size,m_SelectInfo.size,viewport);
00238         }
00239         
00240         Cam.DoProjection();
00241         
00242         glEnable(GL_BLEND);
00243         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  
00244         glEnable(GL_LIGHTING);
00245         
00246         glEnable(GL_CULL_FACE);
00247         glCullFace(GL_BACK);
00248         glFrontFace(GL_CCW);         
00249         
00250         glEnable(GL_RESCALE_NORMAL);
00251         glDisable(GL_COLOR_MATERIAL);
00252 
00253         glEnableClientState(GL_VERTEX_ARRAY);
00254         glEnableClientState(GL_NORMAL_ARRAY);
00255         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
00256         glEnableClientState(GL_COLOR_ARRAY);
00257         glEnable(GL_POLYGON_OFFSET);
00258         
00259         if (m_FogDensity>0)
00260         {
00261             glEnable(GL_FOG);
00262             glFogf(GL_FOG_MODE, GL_EXP);
00263             glFogfv(GL_FOG_COLOR, m_FogColour.arr());
00264             glFogf(GL_FOG_DENSITY, m_FogDensity);
00265             glFogf(GL_FOG_HINT, GL_DONT_CARE);
00266             glFogf(GL_FOG_START, m_FogStart);
00267             glFogf(GL_FOG_END, m_FogEnd);
00268         }
00269         else
00270         {
00271             glDisable(GL_FOG);
00272         }   
00273             
00274         glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR);
00275     
00276         TexturePainter::Get()->Initialise();
00277         
00278         m_Initialised=true;
00279     }
00280     
00281     if (!m_InitLights)
00282     {
00283         // builds the default camera light
00284         ClearLights();
00285         m_InitLights=true;
00286     }
00287     
00288     
00289     glMatrixMode (GL_MODELVIEW);
00290     glLoadIdentity();
00291     
00292     PushState();
00293     
00294     if (m_MotionBlur)
00295     {
00296         glEnable(GL_COLOR_MATERIAL);
00297         glPolygonMode(GL_FRONT,GL_FILL);
00298         glDisable(GL_DEPTH_TEST);
00299         glPushMatrix();
00300         glTranslatef(0,0,-10);
00301         glBegin(GL_QUADS);
00302             glColor4f(m_BGColour.r,m_BGColour.g,m_BGColour.b,m_Fade);
00303             glVertex3f(-10,-10,0);
00304             glVertex3f(10,-10,0);
00305             glVertex3f(10,10,0);
00306             glVertex3f(-10,10,0);
00307         glEnd();
00308         glPopMatrix();
00309         glEnable(GL_DEPTH_TEST);
00310         glDisable(GL_COLOR_MATERIAL);
00311     }
00312         
00313     if (m_FPSDisplay && !PickMode)
00314     {
00315         PushState();
00316         GetState()->Transform.translate(Cam.GetUp(),Cam.GetLeft(),0);
00317         GetState()->Colour=dColour(0,0,1);
00318         char s[32];
00319         sprintf(s,"%f fps",FPS);
00320         DrawText(s);
00321         PopState();
00322     }
00323 
00324     RenderLights(true); // camera locked
00325     Cam.DoCamera();
00326     RenderLights(false); // world space
00327     
00328     glColorMask(m_MaskRed,m_MaskGreen,m_MaskBlue,m_MaskAlpha);
00329 }
00330 
00331 
00332 void Renderer::PostRender()
00333 {
00334     // clear the texture, if the last primitive assigned one...
00335     glDisable(GL_TEXTURE_2D);
00336     glDisable(GL_TEXTURE_CUBE_MAP);
00337     GLSLShader::Unapply();
00338     glFrontFace(GL_CCW);
00339 
00340     glDisable(GL_DEPTH_TEST);
00341     if (m_ShowAxis) Primitive::RenderAxes();
00342     glEnable(GL_DEPTH_TEST);
00343     glColorMask(true,true,true,true);
00344     
00345     PopState();
00346     
00347     if (m_FPSDisplay)
00348     {
00349         if (!(TimeCounter%FRAMES_PER_TIME))
00350         {
00351             timeval TimeNow;
00352             gettimeofday(&TimeNow,NULL);    
00353             FPS = (TimeNow.tv_sec-StartTime.tv_sec)+(TimeNow.tv_usec-StartTime.tv_usec)*0.000001f;
00354             FPS/=(float)FRAMES_PER_TIME;
00355             FPS=1/FPS;  
00356             gettimeofday(&StartTime,NULL);
00357         }
00358         TimeCounter++;
00359     }
00360     
00361     //if (m_StateStack.size()!=1)
00362     //{
00363     //  Trace::Stream<<"State mismatch: stack size "<<m_StateStack.size()<<" at end scene"<<endl;
00364     //}
00365 }
00366 
00367 void Renderer::RenderLights(bool camera)
00368 {
00369     int n=0;
00370     for (vector<Light*>::iterator i=m_LightVec.begin(); i!=m_LightVec.end(); i++)
00371     {
00372         if (n<MAXLIGHTS && (*i)->GetCameraLock()==camera) 
00373         {
00374             (*i)->Render();
00375         }
00376         n++;
00377     }
00378 }
00379 
00380 int Renderer::AddLight(Light *l)
00381 {
00382     l->SetIndex(m_LightVec.size());
00383     m_LightVec.push_back(l);
00384     return m_LightVec.size()-1;
00385 }
00386 
00387 Light *Renderer::GetLight(int id)
00388 {
00389     if (id<(int)m_LightVec.size()) return m_LightVec[id];
00390     else return NULL;
00391 }
00392 
00393 void Renderer::ClearLights()
00394 {
00395     for (unsigned int n=0; n<m_LightVec.size(); n++)
00396     {
00397         glDisable(GL_LIGHT0+n);
00398     }
00399     
00400     m_LightVec.clear();
00401     
00402     // add a default light
00403     Light *light=new Light;
00404     light->SetPosition(dVector(0,0,0));
00405     light->SetCameraLock(true);
00406     AddLight(light);
00407 }
00408 
00409 int Renderer::Select(unsigned int CamIndex, int x, int y, int size)
00410 {
00411     static const int SELECT_SIZE=512;
00412     unsigned int IDs[SELECT_SIZE];
00413     memset(IDs,0,SELECT_SIZE);
00414     GLuint ID=0;
00415     glSelectBuffer(SELECT_SIZE,(GLuint*)IDs);
00416     glRenderMode(GL_SELECT);
00417     glInitNames();
00418     
00419     m_SelectInfo.x=x;
00420     m_SelectInfo.y=y;
00421     m_SelectInfo.size=size;
00422     
00423     // the problem here is that select is called mid-scene, so we have to set up for 
00424     // picking mode here...
00425     PreRender(CamIndex,true);
00426     
00427     // render the scene for picking
00428     m_World.Render(&m_ShadowVolumeGen,SceneGraph::SELECT);
00429     
00430     int hits=glRenderMode(GL_RENDER);
00431     unsigned int *ptr=IDs, numnames;
00432     float minz,maxz,closest=1000000;
00433 
00434     // process the hit records
00435     for (int n=0; n<hits; n++)
00436     {
00437         numnames=*ptr;
00438         ptr++;
00439         minz = (float) *ptr++/0x7fffffff;
00440         maxz = (float) *ptr++/0x7fffffff;
00441                 
00442         // find the closest one
00443         if (closest>minz) 
00444         {
00445             closest=minz;
00446             ID=*ptr;
00447         }
00448         for (unsigned int i=0; i<numnames; i++) *ptr++;
00449     }
00450     
00451     // ... and reset the scene back here so we can carry on afterwards as if nothing
00452     // has happened...
00453     m_Initialised=false;
00454     PreRender(CamIndex);
00455     
00456     return ID;
00457 }
00458 
00459 int Renderer::AddPrimitive(Primitive *Prim)
00460 {
00461     Prim->SetState(GetState());
00462     SceneNode *node = new SceneNode(Prim);
00463     return m_World.AddNode(GetState()->Parent,node);
00464 }
00465 
00466 Primitive *Renderer::GetPrimitive(int ID)
00467 {
00468     SceneNode *node = (SceneNode*)m_World.FindNode(ID);
00469     if (node==NULL) return NULL;
00470     return node->Prim;
00471 }
00472 
00473 void Renderer::RemovePrimitive(int ID)
00474 {
00475     SceneNode *node = (SceneNode*)m_World.FindNode(ID);
00476     if (node!=NULL)
00477     {
00478         if (node->Prim==m_Grabbed) UnGrab();
00479         m_World.RemoveNode(node);
00480     }
00481 }
00482 
00483 void Renderer::DetachPrimitive(int ID)
00484 {
00485     SceneNode *node=(SceneNode*)m_World.FindNode(ID);
00486     if (node) m_World.Detach(node);
00487 }
00488 
00489 // immediate mode
00490 void Renderer::RenderPrimitive(Primitive *Prim)
00491 {   
00492     m_ImmediateMode.Add(Prim,GetState());
00493 }
00494 
00495 dMatrix Renderer::GetGlobalTransform(int ID)
00496 {
00497     dMatrix mat;
00498     SceneNode *node=(SceneNode*)m_World.FindNode(ID);
00499     if (node) mat=m_World.GetGlobalTransform(node);
00500     return mat;
00501 }
00502 
00503 dBoundingBox Renderer::GetBoundingBox(int ID)
00504 {
00505     dBoundingBox bbox;
00506     SceneNode *node=(SceneNode*)m_World.FindNode(ID);
00507     if (node) m_World.GetBoundingBox(node,bbox);
00508     return bbox;
00509 }
00510 
00512 // state accessors
00513 State *Renderer::GetState()
00514 {
00515     if (m_StateStack.empty())
00516     {
00517         Trace::Stream<<"Renderer::GetState : State stack is empty"<<endl;
00518         return NULL;
00519     }
00520     
00521     return &(*m_StateStack.begin());
00522 }
00523 
00524 void Renderer::ApplyState()
00525 {
00526     GetState()->Apply();
00527 }
00528 
00529 void Renderer::PushState()
00530 {
00531     #ifdef DEBUG_TRACE
00532     Trace::Stream<<"Renderer::PushState"<<endl;
00533     #endif
00534     
00535     m_StateStack.push_front(*GetState());
00536 }
00537 
00538 void Renderer::PopState()
00539 {
00540     #ifdef DEBUG_TRACE
00541     Trace::Stream<<"Renderer::PopState"<<endl;
00542     #endif
00543     
00544     if (m_StateStack.size()<2)
00545     {
00546         Trace::Stream<<"Renderer::PopState : only one state left, not popping"<<endl;
00547     }
00548     else
00549     {
00550         m_StateStack.pop_front();
00551     }
00552 }
00553 
00554 void Renderer::Grab(int ID)
00555 {
00556     SceneNode *n=(SceneNode *)m_World.FindNode(ID);
00557     if (n)
00558     {
00559         Primitive *p=n->Prim;
00560         if (p)
00561         {
00562             m_Grabbed=p;
00563         }
00564     }
00565 }
00566 
00567 void Renderer::UnGrab()
00568 {
00569     m_Grabbed=NULL;
00570 }
00571 
00572 //void Renderer::Apply(int id)
00573 //{
00574 //  Primitive *p = GetPrimitive(id);
00575 //  if (p) p->ApplyTransform();
00576 //}
00577 
00578 void Renderer::DrawText(const string &Text)
00579 {
00580     glPushMatrix(); 
00581     GetState()->Apply();
00582     //glDisable(GL_DEPTH_TEST);
00583     glDisable(GL_LIGHTING);
00584     glPushMatrix();
00585     glRasterPos3f(0.0, 0.0, -1.1);
00586     for (unsigned int n=0; n<Text.length(); n++)
00587     {
00588         glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, Text.c_str()[n]);
00589         glTranslatef(1.0f,0.0f,0.0f);
00590     }
00591     glPopMatrix();
00592     glEnable(GL_LIGHTING);
00593     //glEnable(GL_DEPTH_TEST);
00594     glPopMatrix();  
00595 }
00596 
00597 void Renderer::ShowCursor(bool s)
00598 {
00599     if (s)
00600     {
00601         glutSetCursor(GLUT_CURSOR_INHERIT); 
00602     }
00603     else 
00604     {
00605         glutSetCursor(GLUT_CURSOR_NONE); 
00606     }
00607 
00608 }
00609 
00610 void Renderer::DrawBuffer(GLenum mode)
00611 {
00612     glDrawBuffer(mode);
00613 }
00614 
00615 void Renderer::ReadBuffer(GLenum mode)
00616 {
00617     glReadBuffer(mode);
00618 }
00619 
00620 bool Renderer::SetStereoMode(stereo_mode_t mode)
00621 {
00622     GLboolean stereoWindowTest;
00623     switch(mode){
00624         case noStereo: m_StereoMode = noStereo;
00625             return true;
00626         case crystalEyes:
00627             //test for a stereo window
00628             glGetBooleanv (GL_STEREO, &stereoWindowTest);
00629             if(stereoWindowTest){
00630                 m_StereoMode = crystalEyes;
00631                 return true;
00632             } else {
00633                 m_StereoMode = noStereo;
00634                 return false;
00635             }
00636         case colourStereo:
00637             m_StereoMode = colourStereo;
00638             return true;
00639     };
00640     return false;
00641 }
00642 
00643 void Renderer::SetColourMask(bool inred, bool ingreen, bool inblue, bool inalpha)
00644 {
00645     m_MaskRed=inred;
00646     m_MaskGreen=ingreen;
00647     m_MaskBlue=inblue;
00648     m_MaskAlpha=inalpha;
00649 }
00650 
00651 void Renderer::Accum(int mode, float factor)
00652 {
00653     glAccum(mode,factor);
00654 }
00655 
00656 void Renderer::PrintInfo()
00657 {
00658     Trace::Stream<<"Fluxus Version "<<FLUXUS_MAJOR_VERSION<<"."<<FLUXUS_MINOR_VERSION<<endl;
00659     Trace::Stream<<"Textures Cached:"<<endl;
00660     TexturePainter::Get()->Dump();
00661     Trace::Stream<<"Primitives Cached:"<<endl;
00662     PrimitiveIO::Dump();
00663     Trace::Stream<<"Shaders cached:"<<endl;
00664     ShaderCache::Dump();    
00665     Trace::Stream<<"Scenegraph:"<<endl;
00666     m_World.Dump(); 
00667 }

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