Blender V2.61 - r43446

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