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

Generated on Mon Feb 11 06:54:25 2008 for The Fluxus Renderer (libfluxus) by  doxygen 1.5.1