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