Blender V2.61 - r43446

GPC_RenderTools.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 "BKE_bmfont.h" // for text printing
00055 #include "BKE_bmfont_types.h"
00056 
00057 #include "GPC_RenderTools.h"
00058 
00059 extern "C" {
00060 #include "BLF_api.h"
00061 }
00062 
00063 
00064 unsigned int GPC_RenderTools::m_numgllights;
00065 
00066 GPC_RenderTools::GPC_RenderTools()
00067 {
00068 // XXX  m_font = BMF_GetFont(BMF_kHelvetica10);
00069 
00070     glGetIntegerv(GL_MAX_LIGHTS, (GLint*) &m_numgllights);
00071     if (m_numgllights < 8)
00072         m_numgllights = 8;
00073 }
00074 
00075 GPC_RenderTools::~GPC_RenderTools()
00076 {
00077 }
00078 
00079 void GPC_RenderTools::BeginFrame(RAS_IRasterizer* rasty)
00080 {
00081     m_clientobject = NULL;
00082     m_lastlightlayer = -1;
00083     m_lastauxinfo = NULL;
00084     m_lastlighting = true; /* force disable in DisableOpenGLLights() */
00085     DisableOpenGLLights();
00086 }
00087 
00088 void GPC_RenderTools::EndFrame(RAS_IRasterizer* rasty)
00089 {
00090 }
00091 
00092 /* ProcessLighting performs lighting on objects. the layer is a bitfield that
00093  * contains layer information. There are 20 'official' layers in blender. A
00094  * light is applied on an object only when they are in the same layer. OpenGL
00095  * has a maximum of 8 lights (simultaneous), so 20 * 8 lights are possible in
00096  * a scene. */
00097 
00098 void GPC_RenderTools::ProcessLighting(RAS_IRasterizer *rasty, bool uselights, const MT_Transform& viewmat)
00099 {
00100     bool enable = false;
00101     int layer= -1;
00102 
00103     /* find the layer */
00104     if(uselights) {
00105         if(m_clientobject)
00106             layer = static_cast<KX_GameObject*>(m_clientobject)->GetLayer();
00107     }
00108 
00109     /* avoid state switching */
00110     if(m_lastlightlayer == layer && m_lastauxinfo == m_auxilaryClientInfo)
00111         return;
00112 
00113     m_lastlightlayer = layer;
00114     m_lastauxinfo = m_auxilaryClientInfo;
00115 
00116     /* enable/disable lights as needed */
00117     if(layer >= 0)
00118         enable = applyLights(layer, viewmat);
00119 
00120     if(enable)
00121         EnableOpenGLLights(rasty);
00122     else
00123         DisableOpenGLLights();
00124 }
00125 
00126 void GPC_RenderTools::EnableOpenGLLights(RAS_IRasterizer *rasty)
00127 {
00128     if(m_lastlighting == true)
00129         return;
00130 
00131     glEnable(GL_LIGHTING);
00132     glEnable(GL_COLOR_MATERIAL);
00133 
00134     glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
00135     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
00136     glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (rasty->GetCameraOrtho())? GL_FALSE: GL_TRUE);
00137     if (GLEW_EXT_separate_specular_color || GLEW_VERSION_1_2)
00138         glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
00139     
00140     m_lastlighting = true;
00141 }
00142 
00143 void GPC_RenderTools::DisableOpenGLLights()
00144 {
00145     if(m_lastlighting == false)
00146         return;
00147 
00148     glDisable(GL_LIGHTING);
00149     glDisable(GL_COLOR_MATERIAL);
00150 
00151     m_lastlighting = false;
00152 }
00153 
00154 
00155 void GPC_RenderTools::SetClientObject(RAS_IRasterizer *rasty, void* obj)
00156 {
00157     if (m_clientobject != obj)
00158     {
00159         bool ccw = (obj == NULL || !((KX_GameObject*)obj)->IsNegativeScaling());
00160         rasty->SetFrontFace(ccw);
00161 
00162         m_clientobject = obj;
00163     }
00164 }
00165 
00166 bool GPC_RenderTools::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data)
00167 {
00168     double* const oglmatrix = (double* const) data;
00169     MT_Point3 resultpoint(result->m_hitPoint);
00170     MT_Vector3 resultnormal(result->m_hitNormal);
00171     MT_Vector3 left(oglmatrix[0],oglmatrix[1],oglmatrix[2]);
00172     MT_Vector3 dir = -(left.cross(resultnormal)).safe_normalized();
00173     left = (dir.cross(resultnormal)).safe_normalized();
00174     // for the up vector, we take the 'resultnormal' returned by the physics
00175     
00176     double maat[16]={
00177             left[0],        left[1],        left[2], 0,
00178                 dir[0],         dir[1],         dir[2], 0,
00179         resultnormal[0],resultnormal[1],resultnormal[2], 0,
00180                 0,              0,              0, 1};
00181     glTranslated(resultpoint[0],resultpoint[1],resultpoint[2]);
00182     //glMultMatrixd(oglmatrix);
00183     glMultMatrixd(maat);
00184     return true;
00185 }
00186 
00187 void GPC_RenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmatrix,int objectdrawmode )
00188 {
00189     /* FIXME:
00190     blender: intern/moto/include/MT_Vector3.inl:42: MT_Vector3 operator/(const
00191     MT_Vector3&, double): Assertion `!MT_fuzzyZero(s)' failed. 
00192     
00193     Program received signal SIGABRT, Aborted. 
00194     [Switching to Thread 16384 (LWP 1519)] 
00195     0x40477571 in kill () from /lib/libc.so.6 
00196     (gdb) bt 
00197     #7  0x08334368 in MT_Vector3::normalized() const () 
00198     #8  0x0833e6ec in GPC_RenderTools::applyTransform(RAS_IRasterizer*, double*, int) () 
00199     */
00200 
00201     if (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED ||
00202         objectdrawmode & RAS_IPolyMaterial::BILLBOARD_AXISALIGNED)
00203     {
00204         // rotate the billboard/halo
00205         //page 360/361 3D Game Engine Design, David Eberly for a discussion
00206         // on screen aligned and axis aligned billboards
00207         // assumed is that the preprocessor transformed all billboard polygons
00208         // so that their normal points into the positive x direction (1.0 , 0.0 , 0.0)
00209         // when new parenting for objects is done, this rotation
00210         // will be moved into the object
00211         
00212         MT_Point3 objpos (oglmatrix[12],oglmatrix[13],oglmatrix[14]);
00213         MT_Point3 campos = rasty->GetCameraPosition();
00214         MT_Vector3 dir = (campos - objpos).safe_normalized();
00215         MT_Vector3 up(0,0,1.0);
00216 
00217         KX_GameObject* gameobj = (KX_GameObject*) this->m_clientobject;
00218         // get scaling of halo object
00219         MT_Vector3  size = gameobj->GetSGNode()->GetLocalScale();
00220         
00221         bool screenaligned = (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED)!=0;//false; //either screen or axisaligned
00222         if (screenaligned)
00223         {
00224             up = (up - up.dot(dir) * dir).safe_normalized();
00225         } else
00226         {
00227             dir = (dir - up.dot(dir)*up).safe_normalized();
00228         }
00229 
00230         MT_Vector3 left = dir.normalized();
00231         dir = (left.cross(up)).normalized();
00232 
00233         // we have calculated the row vectors, now we keep
00234         // local scaling into account:
00235 
00236         left *= size[0];
00237         dir  *= size[1];
00238         up   *= size[2];
00239         double maat[16]={
00240             left[0], left[1],left[2], 0,
00241                 dir[0], dir[1],dir[2],0,
00242                 up[0],up[1],up[2],0,
00243                 0,0,0,1};
00244             glTranslated(objpos[0],objpos[1],objpos[2]);
00245             glMultMatrixd(maat);
00246             
00247     } else
00248     {
00249         if (objectdrawmode & RAS_IPolyMaterial::SHADOW)
00250         {
00251             // shadow must be cast to the ground, physics system needed here!
00252             MT_Point3 frompoint(oglmatrix[12],oglmatrix[13],oglmatrix[14]);
00253             KX_GameObject *gameobj = (KX_GameObject*) this->m_clientobject;
00254             MT_Vector3 direction = MT_Vector3(0,0,-1);
00255 
00256             direction.normalize();
00257             direction *= 100000;
00258 
00259             MT_Point3 topoint = frompoint + direction;
00260 
00261             KX_Scene* kxscene = (KX_Scene*) m_auxilaryClientInfo;
00262             PHY_IPhysicsEnvironment* physics_environment = kxscene->GetPhysicsEnvironment();
00263             KX_IPhysicsController* physics_controller = gameobj->GetPhysicsController();
00264             
00265             KX_GameObject *parent = gameobj->GetParent();
00266             if (!physics_controller && parent)
00267                 physics_controller = parent->GetPhysicsController();
00268             if (parent)
00269                 parent->Release();
00270                 
00271             KX_RayCast::Callback<GPC_RenderTools> callback(this, physics_controller, oglmatrix);
00272             if (!KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback))
00273             {
00274                 // couldn't find something to cast the shadow on...
00275                 glMultMatrixd(oglmatrix);
00276             }
00277         } else
00278         {
00279 
00280             // 'normal' object
00281             glMultMatrixd(oglmatrix);
00282         }
00283     }
00284 }
00285 
00286 void GPC_RenderTools::RenderText3D( int fontid,
00287                                     const char* text,
00288                                     int size,
00289                                     int dpi,
00290                                     float* color,
00291                                     double* mat,
00292                                     float aspect)
00293 {
00294     /* the actual drawing */
00295     glColor3fv(color);
00296  
00297     /* multiply the text matrix by the object matrix */
00298     BLF_enable(fontid, BLF_MATRIX|BLF_ASPECT);
00299     BLF_matrix(fontid, mat);
00300 
00301     /* aspect is the inverse scale that allows you to increase */
00302     /* your resolution without sizing the final text size */
00303     /* the bigger the size, the smaller the aspect  */
00304     BLF_aspect(fontid, aspect, aspect, aspect);
00305 
00306     BLF_size(fontid, size, dpi);
00307     BLF_position(fontid, 0, 0, 0);
00308     BLF_draw(fontid, text, 65535);
00309 
00310     BLF_disable(fontid, BLF_MATRIX|BLF_ASPECT);
00311     glEnable(GL_DEPTH_TEST);
00312 }
00313 
00314 
00315 
00316 void GPC_RenderTools::RenderText2D(RAS_TEXT_RENDER_MODE mode,
00317                                          const char* text,
00318                                          int xco,
00319                                          int yco,                                    
00320                                          int width,
00321                                          int height)
00322 {
00323     /*
00324     STR_String tmpstr(text);
00325     char* s = tmpstr.Ptr(); */
00326 
00327     // Save and change OpenGL settings
00328     int texture2D;
00329     glGetIntegerv(GL_TEXTURE_2D, (GLint*)&texture2D);
00330     glDisable(GL_TEXTURE_2D);
00331     int fog;
00332     glGetIntegerv(GL_FOG, (GLint*)&fog);
00333     glDisable(GL_FOG);
00334     
00335     int light;
00336     glGetIntegerv(GL_LIGHTING, (GLint*)&light);
00337     glDisable(GL_LIGHTING);
00338 
00339     
00340     // Set up viewing settings
00341     glMatrixMode(GL_PROJECTION);
00342     glPushMatrix();
00343     glLoadIdentity();
00344     glOrtho(0, width, 0, height, -1, 1);
00345     glMatrixMode(GL_MODELVIEW);
00346     glPushMatrix();
00347     glLoadIdentity();
00348 
00349     // Actual drawing (draw black first if padded)
00350     if (mode == RAS_IRenderTools::RAS_TEXT_PADDED)
00351     {
00352         glColor3ub(0, 0, 0);
00353         BLF_draw_default(xco+1, height-yco-1, 0.f, text, 65536);
00354     }
00355 
00356     glColor3ub(255, 255, 255);
00357     BLF_draw_default(xco, height-yco, 0.f, text, 65536);
00358 
00359     // Restore view settings
00360     glMatrixMode(GL_PROJECTION);
00361     glPopMatrix();
00362     glMatrixMode(GL_MODELVIEW);
00363     glPopMatrix();
00364 
00365     // Restore OpenGL Settings
00366     if (fog)
00367         glEnable(GL_FOG);
00368     else
00369         glDisable(GL_FOG);
00370     
00371     if (texture2D)
00372         glEnable(GL_TEXTURE_2D);
00373     else
00374         glDisable(GL_TEXTURE_2D);
00375     if (light)
00376         glEnable(GL_LIGHTING);
00377     else
00378         glDisable(GL_LIGHTING);
00379 }
00380 
00381 /* Render Text renders text into a (series of) polygon, using a texture font,
00382  * Each character consists of one polygon (one quad or two triangles) */
00383 
00384 void GPC_RenderTools::RenderText(
00385     int mode,
00386     RAS_IPolyMaterial* polymat,
00387     float v1[3], float v2[3], float v3[3], float v4[3], int glattrib)
00388 {
00389     STR_String mytext = ((CValue*)m_clientobject)->GetPropertyText("Text");
00390     
00391     const unsigned int flag = polymat->GetFlag();
00392     struct MTFace* tface = 0;
00393     unsigned int *col = 0;
00394 
00395     if(flag & RAS_BLENDERMAT) {
00396         KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial*>(polymat);
00397         tface = bl_mat->GetMTFace();
00398         col = bl_mat->GetMCol();
00399     } else {
00400         KX_PolygonMaterial* blenderpoly = static_cast<KX_PolygonMaterial*>(polymat);
00401         tface = blenderpoly->GetMTFace();
00402         col = blenderpoly->GetMCol();
00403     }
00404     
00405     GPU_render_text(tface, mode, mytext, mytext.Length(), col, v1, v2, v3, v4, glattrib);
00406 }
00407 
00408 
00409 void GPC_RenderTools::PushMatrix()
00410 {
00411     glPushMatrix();
00412 }
00413 
00414 void GPC_RenderTools::PopMatrix()
00415 {
00416     glPopMatrix();
00417 }
00418 
00419 
00420 int GPC_RenderTools::applyLights(int objectlayer, const MT_Transform& viewmat)
00421 {
00422     // taken from blender source, incompatibility between Blender Object / GameObject   
00423     KX_Scene* kxscene = (KX_Scene*)m_auxilaryClientInfo;
00424     float glviewmat[16];
00425     unsigned int count;
00426     std::vector<struct  RAS_LightObject*>::iterator lit = m_lights.begin();
00427 
00428     for(count=0; count<m_numgllights; count++)
00429         glDisable((GLenum)(GL_LIGHT0+count));
00430 
00431     viewmat.getValue(glviewmat);
00432     
00433     glPushMatrix();
00434     glLoadMatrixf(glviewmat);
00435     for (lit = m_lights.begin(), count = 0; !(lit==m_lights.end()) && count < m_numgllights; ++lit)
00436     {
00437         RAS_LightObject* lightdata = (*lit);
00438         KX_LightObject *kxlight = (KX_LightObject*)lightdata->m_light;
00439 
00440         if(kxlight->ApplyLight(kxscene, objectlayer, count))
00441             count++;
00442     }
00443     glPopMatrix();
00444 
00445     return count;
00446 }
00447 
00448 void GPC_RenderTools::MotionBlur(RAS_IRasterizer* rasterizer)
00449 {
00450     int state = rasterizer->GetMotionBlurState();
00451     float motionblurvalue;
00452     if(state)
00453     {
00454         motionblurvalue = rasterizer->GetMotionBlurValue();
00455         if(state==1)
00456         {
00457             //bugfix:load color buffer into accum buffer for the first time(state=1)
00458             glAccum(GL_LOAD, 1.0);
00459             rasterizer->SetMotionBlurState(2);
00460         }
00461         else if(motionblurvalue>=0.0 && motionblurvalue<=1.0)
00462         {
00463             glAccum(GL_MULT, motionblurvalue);
00464             glAccum(GL_ACCUM, 1-motionblurvalue);
00465             glAccum(GL_RETURN, 1.0);
00466             glFlush();
00467         }
00468     }
00469 }
00470