Blender V2.61 - r43446

KX_BlenderRenderTools.cpp

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include "GL/glew.h"
00034 
00035 #include "RAS_IRenderTools.h"
00036 #include "RAS_IRasterizer.h"
00037 #include "RAS_LightObject.h"
00038 #include "RAS_ICanvas.h"
00039 #include "RAS_GLExtensionManager.h"
00040 
00041 #include "KX_GameObject.h"
00042 #include "KX_PolygonMaterial.h"
00043 #include "KX_BlenderMaterial.h"
00044 #include "KX_RayCast.h"
00045 #include "KX_IPhysicsController.h"
00046 #include "KX_Light.h"
00047 
00048 #include "PHY_IPhysicsEnvironment.h"
00049 
00050 #include "STR_String.h"
00051 
00052 #include "GPU_draw.h"
00053 
00054 #include "KX_BlenderGL.h" // for text printing
00055 #include "KX_BlenderRenderTools.h"
00056 
00057 unsigned int KX_BlenderRenderTools::m_numgllights;
00058 
00059 KX_BlenderRenderTools::KX_BlenderRenderTools()
00060 {
00061     glGetIntegerv(GL_MAX_LIGHTS, (GLint*) &m_numgllights);
00062     if (m_numgllights < 8)
00063         m_numgllights = 8;
00064 }
00065 
00066 KX_BlenderRenderTools::~KX_BlenderRenderTools()
00067 {
00068 }
00069 
00070 void KX_BlenderRenderTools::BeginFrame(RAS_IRasterizer* rasty)
00071 {
00072     m_clientobject = NULL;
00073     m_lastlightlayer = -1;
00074     m_lastauxinfo = NULL;
00075     m_lastlighting = true; /* force disable in DisableOpenGLLights() */
00076     DisableOpenGLLights();
00077 }
00078 
00079 void KX_BlenderRenderTools::EndFrame(RAS_IRasterizer* rasty)
00080 {
00081 }
00082 
00083 /* ProcessLighting performs lighting on objects. the layer is a bitfield that
00084  * contains layer information. There are 20 'official' layers in blender. A
00085  * light is applied on an object only when they are in the same layer. OpenGL
00086  * has a maximum of 8 lights (simultaneous), so 20 * 8 lights are possible in
00087  * a scene. */
00088 
00089 void KX_BlenderRenderTools::ProcessLighting(RAS_IRasterizer *rasty, bool uselights, const MT_Transform& viewmat)
00090 {
00091     bool enable = false;
00092     int layer= -1;
00093 
00094     /* find the layer */
00095     if(uselights) {
00096         if(m_clientobject)
00097             layer = static_cast<KX_GameObject*>(m_clientobject)->GetLayer();
00098     }
00099 
00100     /* avoid state switching */
00101     if(m_lastlightlayer == layer && m_lastauxinfo == m_auxilaryClientInfo)
00102         return;
00103 
00104     m_lastlightlayer = layer;
00105     m_lastauxinfo = m_auxilaryClientInfo;
00106 
00107     /* enable/disable lights as needed */
00108     if(layer >= 0)
00109         enable = applyLights(layer, viewmat);
00110 
00111     if(enable)
00112         EnableOpenGLLights(rasty);
00113     else
00114         DisableOpenGLLights();
00115 }
00116 
00117 void KX_BlenderRenderTools::EnableOpenGLLights(RAS_IRasterizer *rasty)
00118 {
00119     if(m_lastlighting == true)
00120         return;
00121 
00122     glEnable(GL_LIGHTING);
00123     glEnable(GL_COLOR_MATERIAL);
00124 
00125     glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
00126     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
00127     glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (rasty->GetCameraOrtho())? GL_FALSE: GL_TRUE);
00128     if (GLEW_EXT_separate_specular_color || GLEW_VERSION_1_2)
00129         glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
00130     
00131     m_lastlighting = true;
00132 }
00133 
00134 void KX_BlenderRenderTools::DisableOpenGLLights()
00135 {
00136     if(m_lastlighting == false)
00137         return;
00138 
00139     glDisable(GL_LIGHTING);
00140     glDisable(GL_COLOR_MATERIAL);
00141 
00142     m_lastlighting = false;
00143 }
00144 
00145 
00146 void KX_BlenderRenderTools::SetClientObject(RAS_IRasterizer *rasty, void* obj)
00147 {
00148     if (m_clientobject != obj)
00149     {
00150         bool ccw = (obj == NULL || !((KX_GameObject*)obj)->IsNegativeScaling());
00151         rasty->SetFrontFace(ccw);
00152 
00153         m_clientobject = obj;
00154     }
00155 }
00156 
00157 bool KX_BlenderRenderTools::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data)
00158 {
00159     double* const oglmatrix = (double* const) data;
00160     MT_Point3 resultpoint(result->m_hitPoint);
00161     MT_Vector3 resultnormal(result->m_hitNormal);
00162     MT_Vector3 left(oglmatrix[0],oglmatrix[1],oglmatrix[2]);
00163     MT_Vector3 dir = -(left.cross(resultnormal)).safe_normalized();
00164     left = (dir.cross(resultnormal)).safe_normalized();
00165     // for the up vector, we take the 'resultnormal' returned by the physics
00166     
00167     double maat[16]={
00168             left[0],        left[1],        left[2], 0,
00169                 dir[0],         dir[1],         dir[2], 0,
00170         resultnormal[0],resultnormal[1],resultnormal[2], 0,
00171                 0,              0,              0, 1};
00172     glTranslated(resultpoint[0],resultpoint[1],resultpoint[2]);
00173     //glMultMatrixd(oglmatrix);
00174     glMultMatrixd(maat);
00175     return true;
00176 }
00177 
00178 void KX_BlenderRenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmatrix,int objectdrawmode )
00179 {
00180     /* FIXME:
00181     blender: intern/moto/include/MT_Vector3.inl:42: MT_Vector3 operator/(const
00182     MT_Vector3&, double): Assertion `!MT_fuzzyZero(s)' failed. 
00183     
00184     Program received signal SIGABRT, Aborted. 
00185     [Switching to Thread 16384 (LWP 1519)] 
00186     0x40477571 in kill () from /lib/libc.so.6 
00187     (gdb) bt 
00188     #7  0x08334368 in MT_Vector3::normalized() const () 
00189     #8  0x0833e6ec in KX_BlenderRenderTools::applyTransform(RAS_IRasterizer*, double*, int) () 
00190     */
00191 
00192     if (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED ||
00193         objectdrawmode & RAS_IPolyMaterial::BILLBOARD_AXISALIGNED)
00194     {
00195         // rotate the billboard/halo
00196         //page 360/361 3D Game Engine Design, David Eberly for a discussion
00197         // on screen aligned and axis aligned billboards
00198         // assumed is that the preprocessor transformed all billboard polygons
00199         // so that their normal points into the positive x direction (1.0 , 0.0 , 0.0)
00200         // when new parenting for objects is done, this rotation
00201         // will be moved into the object
00202         
00203         MT_Point3 objpos (oglmatrix[12],oglmatrix[13],oglmatrix[14]);
00204         MT_Point3 campos = rasty->GetCameraPosition();
00205         MT_Vector3 dir = (campos - objpos).safe_normalized();
00206         MT_Vector3 up(0,0,1.0);
00207 
00208         KX_GameObject* gameobj = (KX_GameObject*)m_clientobject;
00209         // get scaling of halo object
00210         MT_Vector3  size = gameobj->GetSGNode()->GetLocalScale();
00211         
00212         bool screenaligned = (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED)!=0;//false; //either screen or axisaligned
00213         if (screenaligned)
00214         {
00215             up = (up - up.dot(dir) * dir).safe_normalized();
00216         } else
00217         {
00218             dir = (dir - up.dot(dir)*up).safe_normalized();
00219         }
00220 
00221         MT_Vector3 left = dir.normalized();
00222         dir = (left.cross(up)).normalized();
00223 
00224         // we have calculated the row vectors, now we keep
00225         // local scaling into account:
00226 
00227         left *= size[0];
00228         dir  *= size[1];
00229         up   *= size[2];
00230         double maat[16]={
00231             left[0], left[1],left[2], 0,
00232                 dir[0], dir[1],dir[2],0,
00233                 up[0],up[1],up[2],0,
00234                 0,0,0,1};
00235             glTranslated(objpos[0],objpos[1],objpos[2]);
00236             glMultMatrixd(maat);
00237             
00238     } else
00239     {
00240         if (objectdrawmode & RAS_IPolyMaterial::SHADOW)
00241         {
00242             // shadow must be cast to the ground, physics system needed here!
00243             MT_Point3 frompoint(oglmatrix[12],oglmatrix[13],oglmatrix[14]);
00244             KX_GameObject *gameobj = (KX_GameObject*)m_clientobject;
00245             MT_Vector3 direction = MT_Vector3(0,0,-1);
00246 
00247             direction.normalize();
00248             direction *= 100000;
00249 
00250             MT_Point3 topoint = frompoint + direction;
00251 
00252             KX_Scene* kxscene = (KX_Scene*) m_auxilaryClientInfo;
00253             PHY_IPhysicsEnvironment* physics_environment = kxscene->GetPhysicsEnvironment();
00254             KX_IPhysicsController* physics_controller = gameobj->GetPhysicsController();
00255             
00256             KX_GameObject *parent = gameobj->GetParent();
00257             if (!physics_controller && parent)
00258                 physics_controller = parent->GetPhysicsController();
00259             if (parent)
00260                 parent->Release();
00261                 
00262             KX_RayCast::Callback<KX_BlenderRenderTools> callback(this, physics_controller, oglmatrix);
00263             if (!KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback))
00264             {
00265                 // couldn't find something to cast the shadow on...
00266                 glMultMatrixd(oglmatrix);
00267             }
00268             else
00269             { // we found the "ground", but the cast matrix doesn't take
00270               // scaling in consideration, so we must apply the object scale
00271                 MT_Vector3  size = gameobj->GetSGNode()->GetLocalScale();
00272                 glScalef(size[0], size[1], size[2]);
00273             }
00274         } else
00275         {
00276 
00277             // 'normal' object
00278             glMultMatrixd(oglmatrix);
00279         }
00280     }
00281 }
00282 void KX_BlenderRenderTools::RenderText3D(int fontid,
00283                                          const char* text,
00284                                          int size,
00285                                          int dpi,
00286                                          float* color,
00287                                          double* mat,
00288                                          float aspect)
00289 {
00290     BL_print_game_line(fontid, text, size, dpi, color, mat, aspect);
00291 }
00292 
00293 void KX_BlenderRenderTools::RenderText2D(RAS_TEXT_RENDER_MODE mode,
00294                                          const char* text,
00295                                          int xco,
00296                                          int yco,                                    
00297                                          int width,
00298                                          int height)
00299 {
00300     if(mode == RAS_IRenderTools::RAS_TEXT_PADDED)
00301         BL_print_gamedebug_line_padded(text, xco, yco, width, height);
00302     else
00303         BL_print_gamedebug_line(text, xco, yco, width, height);
00304 }
00305 
00306 /* Render Text renders text into a (series of) polygon, using a texture font,
00307  * Each character consists of one polygon (one quad or two triangles) */
00308 
00309 void KX_BlenderRenderTools::RenderText(
00310     int mode,
00311     RAS_IPolyMaterial* polymat,
00312     float v1[3], float v2[3], float v3[3], float v4[3], int glattrib)
00313 {
00314     const STR_String& mytext = ((CValue*)m_clientobject)->GetPropertyText("Text");
00315     
00316     const unsigned int flag = polymat->GetFlag();
00317     struct MTFace* tface = 0;
00318     unsigned int *col = 0;
00319 
00320     if(flag & RAS_BLENDERMAT) {
00321         KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial*>(polymat);
00322         tface = bl_mat->GetMTFace();
00323         col = bl_mat->GetMCol();
00324     } else {
00325         KX_PolygonMaterial* blenderpoly = static_cast<KX_PolygonMaterial*>(polymat);
00326         tface = blenderpoly->GetMTFace();
00327         col = blenderpoly->GetMCol();
00328     }
00329     
00330     GPU_render_text(tface, mode, mytext, mytext.Length(), col, v1, v2, v3, v4, glattrib);
00331 }
00332 
00333 
00334 void KX_BlenderRenderTools::PushMatrix()
00335 {
00336     glPushMatrix();
00337 }
00338 
00339 void KX_BlenderRenderTools::PopMatrix()
00340 {
00341     glPopMatrix();
00342 }
00343 
00344 
00345 int KX_BlenderRenderTools::applyLights(int objectlayer, const MT_Transform& viewmat)
00346 {
00347     // taken from blender source, incompatibility between Blender Object / GameObject   
00348     KX_Scene* kxscene = (KX_Scene*)m_auxilaryClientInfo;
00349     float glviewmat[16];
00350     unsigned int count;
00351     std::vector<struct  RAS_LightObject*>::iterator lit = m_lights.begin();
00352 
00353     for(count=0; count<m_numgllights; count++)
00354         glDisable((GLenum)(GL_LIGHT0+count));
00355 
00356     viewmat.getValue(glviewmat);
00357     
00358     glPushMatrix();
00359     glLoadMatrixf(glviewmat);
00360     for (lit = m_lights.begin(), count = 0; !(lit==m_lights.end()) && count < m_numgllights; ++lit)
00361     {
00362         RAS_LightObject* lightdata = (*lit);
00363         KX_LightObject *kxlight = (KX_LightObject*)lightdata->m_light;
00364 
00365         if(kxlight->ApplyLight(kxscene, objectlayer, count))
00366             count++;
00367     }
00368     glPopMatrix();
00369 
00370     return count;
00371 }
00372 
00373 void KX_BlenderRenderTools::MotionBlur(RAS_IRasterizer* rasterizer)
00374 {
00375     int state = rasterizer->GetMotionBlurState();
00376     float motionblurvalue;
00377     if(state)
00378     {
00379         motionblurvalue = rasterizer->GetMotionBlurValue();
00380         if(state==1)
00381         {
00382             //bugfix:load color buffer into accum buffer for the first time(state=1)
00383             glAccum(GL_LOAD, 1.0);
00384             rasterizer->SetMotionBlurState(2);
00385         }
00386         else if(motionblurvalue>=0.0 && motionblurvalue<=1.0)
00387         {
00388             glAccum(GL_MULT, motionblurvalue);
00389             glAccum(GL_ACCUM, 1-motionblurvalue);
00390             glAccum(GL_RETURN, 1.0);
00391             glFlush();
00392         }
00393     }
00394 }