Blender  V2.59
KX_Light.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: KX_Light.cpp 35171 2011-02-25 13:35:59Z jesterking $
00003  * ***** BEGIN GPL LICENSE BLOCK *****
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * as published by the Free Software Foundation; either version 2
00008  * of the License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00020  * All rights reserved.
00021  *
00022  * The Original Code is: all of this file.
00023  *
00024  * Contributor(s): none yet.
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 #if defined(WIN32) && !defined(FREE_WINDOWS)
00035 #pragma warning (disable : 4786)
00036 #endif
00037 
00038 #include "GL/glew.h"
00039 
00040 #include "KX_Light.h"
00041 #include "KX_Camera.h"
00042 #include "RAS_IRasterizer.h"
00043 #include "RAS_IRenderTools.h"
00044 
00045 #include "KX_PyMath.h"
00046 
00047 #include "DNA_object_types.h"
00048 #include "DNA_scene_types.h"
00049 #include "GPU_material.h"
00050  
00051 KX_LightObject::KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,
00052                                                            class RAS_IRenderTools* rendertools,
00053                                                            const RAS_LightObject&       lightobj,
00054                                                            bool glsl)
00055         : KX_GameObject(sgReplicationInfo,callbacks),
00056           m_rendertools(rendertools)
00057 {
00058         m_lightobj = lightobj;
00059         m_lightobj.m_scene = sgReplicationInfo;
00060         m_lightobj.m_light = this;
00061         m_rendertools->AddLight(&m_lightobj);
00062         m_glsl = glsl;
00063         m_blenderscene = ((KX_Scene*)sgReplicationInfo)->GetBlenderScene();
00064 };
00065 
00066 
00067 KX_LightObject::~KX_LightObject()
00068 {
00069         GPULamp *lamp;
00070 
00071         if((lamp = GetGPULamp())) {
00072                 float obmat[4][4] = {{0}};
00073                 GPU_lamp_update(lamp, 0, 0, obmat);
00074         }
00075 
00076         m_rendertools->RemoveLight(&m_lightobj);
00077 }
00078 
00079 
00080 CValue*         KX_LightObject::GetReplica()
00081 {
00082 
00083         KX_LightObject* replica = new KX_LightObject(*this);
00084 
00085         replica->ProcessReplica();
00086         
00087         replica->m_lightobj.m_light = replica;
00088         m_rendertools->AddLight(&replica->m_lightobj);
00089 
00090         return replica;
00091 }
00092 
00093 bool KX_LightObject::ApplyLight(KX_Scene *kxscene, int oblayer, int slot)
00094 {
00095         KX_Scene* lightscene = (KX_Scene*)m_lightobj.m_scene;
00096         float vec[4];
00097         int scenelayer = ~0;
00098 
00099         if(kxscene && kxscene->GetBlenderScene())
00100                 scenelayer = kxscene->GetBlenderScene()->lay;
00101         
00102         /* only use lights in the same layer as the object */
00103         if(!(m_lightobj.m_layer & oblayer))
00104                 return false;
00105         /* only use lights in the same scene, and in a visible layer */
00106         if(kxscene != lightscene || !(m_lightobj.m_layer & scenelayer))
00107                 return false;
00108 
00109         // lights don't get their openGL matrix updated, do it now
00110         if(GetSGNode()->IsDirty())
00111                 GetOpenGLMatrix();
00112 
00113         MT_CmMatrix4x4& worldmatrix= *GetOpenGLMatrixPtr();
00114 
00115         vec[0] = worldmatrix(0,3);
00116         vec[1] = worldmatrix(1,3);
00117         vec[2] = worldmatrix(2,3);
00118         vec[3] = 1.0f;
00119 
00120         if(m_lightobj.m_type==RAS_LightObject::LIGHT_SUN) {
00121                 
00122                 vec[0] = worldmatrix(0,2);
00123                 vec[1] = worldmatrix(1,2);
00124                 vec[2] = worldmatrix(2,2);
00125                 //vec[0]= base->object->obmat[2][0];
00126                 //vec[1]= base->object->obmat[2][1];
00127                 //vec[2]= base->object->obmat[2][2];
00128                 vec[3]= 0.0;
00129                 glLightfv((GLenum)(GL_LIGHT0+slot), GL_POSITION, vec); 
00130         }
00131         else {
00132                 //vec[3]= 1.0;
00133                 glLightfv((GLenum)(GL_LIGHT0+slot), GL_POSITION, vec); 
00134                 glLightf((GLenum)(GL_LIGHT0+slot), GL_CONSTANT_ATTENUATION, 1.0);
00135                 glLightf((GLenum)(GL_LIGHT0+slot), GL_LINEAR_ATTENUATION, m_lightobj.m_att1/m_lightobj.m_distance);
00136                 // without this next line it looks backward compatible.
00137                 //attennuation still is acceptable 
00138                 glLightf((GLenum)(GL_LIGHT0+slot), GL_QUADRATIC_ATTENUATION, m_lightobj.m_att2/(m_lightobj.m_distance*m_lightobj.m_distance)); 
00139                 
00140                 if(m_lightobj.m_type==RAS_LightObject::LIGHT_SPOT) {
00141                         vec[0] = -worldmatrix(0,2);
00142                         vec[1] = -worldmatrix(1,2);
00143                         vec[2] = -worldmatrix(2,2);
00144                         //vec[0]= -base->object->obmat[2][0];
00145                         //vec[1]= -base->object->obmat[2][1];
00146                         //vec[2]= -base->object->obmat[2][2];
00147                         glLightfv((GLenum)(GL_LIGHT0+slot), GL_SPOT_DIRECTION, vec);
00148                         glLightf((GLenum)(GL_LIGHT0+slot), GL_SPOT_CUTOFF, m_lightobj.m_spotsize/2.0);
00149                         glLightf((GLenum)(GL_LIGHT0+slot), GL_SPOT_EXPONENT, 128.0*m_lightobj.m_spotblend);
00150                 }
00151                 else
00152                         glLightf((GLenum)(GL_LIGHT0+slot), GL_SPOT_CUTOFF, 180.0);
00153         }
00154         
00155         if (m_lightobj.m_nodiffuse) {
00156                 vec[0] = vec[1] = vec[2] = vec[3] = 0.0;
00157         }
00158         else {
00159                 vec[0]= m_lightobj.m_energy*m_lightobj.m_red;
00160                 vec[1]= m_lightobj.m_energy*m_lightobj.m_green;
00161                 vec[2]= m_lightobj.m_energy*m_lightobj.m_blue;
00162                 vec[3]= 1.0;
00163         }
00164 
00165         glLightfv((GLenum)(GL_LIGHT0+slot), GL_DIFFUSE, vec);
00166         if(m_lightobj.m_nospecular)
00167         {
00168                 vec[0] = vec[1] = vec[2] = vec[3] = 0.0;
00169         }
00170         else if (m_lightobj.m_nodiffuse) {
00171                 vec[0]= m_lightobj.m_energy*m_lightobj.m_red;
00172                 vec[1]= m_lightobj.m_energy*m_lightobj.m_green;
00173                 vec[2]= m_lightobj.m_energy*m_lightobj.m_blue;
00174                 vec[3]= 1.0;
00175         }
00176 
00177         glLightfv((GLenum)(GL_LIGHT0+slot), GL_SPECULAR, vec);
00178         glEnable((GLenum)(GL_LIGHT0+slot));
00179 
00180         return true;
00181 }
00182 
00183 GPULamp *KX_LightObject::GetGPULamp()
00184 {
00185         if(m_glsl)
00186                 return GPU_lamp_from_blender(m_blenderscene, GetBlenderObject(), GetBlenderGroupObject());
00187         else
00188                 return NULL;
00189 }
00190 
00191 void KX_LightObject::Update()
00192 {
00193         GPULamp *lamp;
00194 
00195         if((lamp = GetGPULamp()) != NULL && GetSGNode()) {
00196                 float obmat[4][4];
00197                 // lights don't get their openGL matrix updated, do it now
00198                 if (GetSGNode()->IsDirty())
00199                         GetOpenGLMatrix();
00200                 double *dobmat = GetOpenGLMatrixPtr()->getPointer();
00201 
00202                 for(int i=0; i<4; i++)
00203                         for(int j=0; j<4; j++, dobmat++)
00204                                 obmat[i][j] = (float)*dobmat;
00205 
00206                 GPU_lamp_update(lamp, m_lightobj.m_layer, 0, obmat);
00207                 GPU_lamp_update_colors(lamp, m_lightobj.m_red, m_lightobj.m_green, 
00208                         m_lightobj.m_blue, m_lightobj.m_energy);
00209         }
00210 }
00211 
00212 bool KX_LightObject::HasShadowBuffer()
00213 {
00214         GPULamp *lamp;
00215 
00216         if((lamp = GetGPULamp()))
00217                 return GPU_lamp_has_shadow_buffer(lamp);
00218         else
00219                 return false;
00220 }
00221 
00222 int KX_LightObject::GetShadowLayer()
00223 {
00224         GPULamp *lamp;
00225 
00226         if((lamp = GetGPULamp()))
00227                 return GPU_lamp_shadow_layer(lamp);
00228         else
00229                 return 0;
00230 }
00231 
00232 void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_Transform& camtrans)
00233 {
00234         GPULamp *lamp;
00235         float viewmat[4][4], winmat[4][4];
00236         int winsize;
00237 
00238         /* bind framebuffer */
00239         lamp = GetGPULamp();
00240         GPU_lamp_shadow_buffer_bind(lamp, viewmat, &winsize, winmat);
00241 
00242         /* setup camera transformation */
00243         MT_Matrix4x4 modelviewmat((float*)viewmat);
00244         MT_Matrix4x4 projectionmat((float*)winmat);
00245 
00246         MT_Transform trans = MT_Transform((float*)viewmat);
00247         camtrans.invert(trans);
00248 
00249         cam->SetModelviewMatrix(modelviewmat);
00250         cam->SetProjectionMatrix(projectionmat);
00251         
00252         cam->NodeSetLocalPosition(camtrans.getOrigin());
00253         cam->NodeSetLocalOrientation(camtrans.getBasis());
00254         cam->NodeUpdateGS(0);
00255 
00256         /* setup rasterizer transformations */
00257         ras->SetProjectionMatrix(projectionmat);
00258         ras->SetViewMatrix(modelviewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective);
00259 }
00260 
00261 void KX_LightObject::UnbindShadowBuffer(RAS_IRasterizer *ras)
00262 {
00263         GPULamp *lamp = GetGPULamp();
00264         GPU_lamp_shadow_buffer_unbind(lamp);
00265 }
00266 
00267 #ifdef WITH_PYTHON
00268 /* ------------------------------------------------------------------------- */
00269 /* Python Integration Hooks                                                                      */
00270 /* ------------------------------------------------------------------------- */
00271 
00272 PyTypeObject KX_LightObject::Type = {
00273         PyVarObject_HEAD_INIT(NULL, 0)
00274         "KX_LightObject",
00275         sizeof(PyObjectPlus_Proxy),
00276         0,
00277         py_base_dealloc,
00278         0,
00279         0,
00280         0,
00281         0,
00282         py_base_repr,
00283         0,
00284         &KX_GameObject::Sequence,
00285         &KX_GameObject::Mapping,
00286         0,0,0,
00287         NULL,
00288         NULL,
00289         0,
00290         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00291         0,0,0,0,0,0,0,
00292         Methods,
00293         0,
00294         0,
00295         &KX_GameObject::Type,
00296         0,0,0,0,0,0,
00297         py_base_new
00298 };
00299 
00300 PyMethodDef KX_LightObject::Methods[] = {
00301         {NULL,NULL} //Sentinel
00302 };
00303 
00304 PyAttributeDef KX_LightObject::Attributes[] = {
00305         KX_PYATTRIBUTE_INT_RW("layer", 1, 20, true, KX_LightObject, m_lightobj.m_layer),
00306         KX_PYATTRIBUTE_FLOAT_RW("energy", 0, 10, KX_LightObject, m_lightobj.m_energy),
00307         KX_PYATTRIBUTE_FLOAT_RW("distance", 0.01, 5000, KX_LightObject, m_lightobj.m_distance),
00308         KX_PYATTRIBUTE_RW_FUNCTION("color", KX_LightObject, pyattr_get_color, pyattr_set_color),
00309         KX_PYATTRIBUTE_FLOAT_RW("lin_attenuation", 0, 1, KX_LightObject, m_lightobj.m_att1),
00310         KX_PYATTRIBUTE_FLOAT_RW("quad_attenuation", 0, 1, KX_LightObject, m_lightobj.m_att2),
00311         KX_PYATTRIBUTE_FLOAT_RW("spotsize", 1, 180, KX_LightObject, m_lightobj.m_spotsize),
00312         KX_PYATTRIBUTE_FLOAT_RW("spotblend", 0, 1, KX_LightObject, m_lightobj.m_spotblend),
00313         KX_PYATTRIBUTE_RO_FUNCTION("SPOT", KX_LightObject, pyattr_get_typeconst),
00314         KX_PYATTRIBUTE_RO_FUNCTION("SUN", KX_LightObject, pyattr_get_typeconst),
00315         KX_PYATTRIBUTE_RO_FUNCTION("NORMAL", KX_LightObject, pyattr_get_typeconst),
00316         KX_PYATTRIBUTE_RW_FUNCTION("type", KX_LightObject, pyattr_get_type, pyattr_set_type),
00317         { NULL }        //Sentinel
00318 };
00319 
00320 PyObject* KX_LightObject::pyattr_get_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00321 {
00322         KX_LightObject* self = static_cast<KX_LightObject*>(self_v);
00323         return Py_BuildValue("[fff]", self->m_lightobj.m_red, self->m_lightobj.m_green, self->m_lightobj.m_blue);
00324 }
00325 
00326 int KX_LightObject::pyattr_set_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00327 {
00328         KX_LightObject* self = static_cast<KX_LightObject*>(self_v);
00329 
00330         MT_Vector3 color;
00331         if (PyVecTo(value, color))
00332         {
00333                 self->m_lightobj.m_red = color[0];
00334                 self->m_lightobj.m_green = color[1];
00335                 self->m_lightobj.m_blue = color[2];
00336                 return PY_SET_ATTR_SUCCESS;
00337         }
00338         return PY_SET_ATTR_FAIL;
00339 }
00340 
00341 PyObject* KX_LightObject::pyattr_get_typeconst(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00342 {
00343         PyObject* retvalue;
00344 
00345         const char* type = attrdef->m_name;
00346 
00347         if(!strcmp(type, "SPOT")) {
00348                 retvalue = PyLong_FromSsize_t(RAS_LightObject::LIGHT_SPOT);
00349         } else if (!strcmp(type, "SUN")) {
00350                 retvalue = PyLong_FromSsize_t(RAS_LightObject::LIGHT_SUN);
00351         } else if (!strcmp(type, "NORMAL")) {
00352                 retvalue = PyLong_FromSsize_t(RAS_LightObject::LIGHT_NORMAL);
00353         }
00354     else {
00355         /* should never happen */
00356         PyErr_SetString(PyExc_TypeError, "light.type: internal error, invalid light type");
00357         retvalue = NULL;
00358     }
00359 
00360         return retvalue;
00361 }
00362 
00363 PyObject* KX_LightObject::pyattr_get_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00364 {
00365         KX_LightObject* self = static_cast<KX_LightObject*>(self_v);
00366         return PyLong_FromSsize_t(self->m_lightobj.m_type);
00367 }
00368 
00369 int KX_LightObject::pyattr_set_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject* value)
00370 {
00371         KX_LightObject* self = static_cast<KX_LightObject*>(self_v);
00372         int val = PyLong_AsSsize_t(value);
00373         if((val==-1 && PyErr_Occurred()) || val<0 || val>2) {
00374                 PyErr_SetString(PyExc_ValueError, "light.type= val: KX_LightObject, expected an int between 0 and 2");
00375                 return PY_SET_ATTR_FAIL;
00376         }
00377         
00378         switch(val) {
00379                 case 0:
00380                         self->m_lightobj.m_type = self->m_lightobj.LIGHT_SPOT;
00381                         break;
00382                 case 1:
00383                         self->m_lightobj.m_type = self->m_lightobj.LIGHT_SUN;
00384                         break;
00385                 case 2:
00386                         self->m_lightobj.m_type = self->m_lightobj.LIGHT_NORMAL;
00387                         break;
00388         }
00389 
00390         return PY_SET_ATTR_SUCCESS;
00391 }
00392 #endif // WITH_PYTHON