Fix for bug #17589: removing a lamp in the game engine with glsl
[blender.git] / source / gameengine / Ketsji / KX_Light.cpp
1 /**
2  * $Id$
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): none yet.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #ifdef WIN32
34
35 #pragma warning (disable : 4786)
36 #endif
37
38 #include "KX_Light.h"
39 #include "KX_Camera.h"
40 #include "RAS_IRasterizer.h"
41 #include "RAS_IRenderTools.h"
42
43 #include "KX_PyMath.h"
44
45 #include "DNA_object_types.h"
46 #include "GPU_material.h"
47  
48 KX_LightObject::KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,
49                                                            class RAS_IRenderTools* rendertools,
50                                                            const RAS_LightObject&       lightobj,
51                                                            bool glsl,
52                                                            PyTypeObject* T
53                                                            )
54  :
55         KX_GameObject(sgReplicationInfo,callbacks,T),
56                 m_rendertools(rendertools)
57 {
58         m_lightobj = lightobj;
59         m_lightobj.m_worldmatrix = GetOpenGLMatrixPtr();
60         m_rendertools->AddLight(&m_lightobj);
61         m_glsl = glsl;
62         m_blenderscene = ((KX_Scene*)sgReplicationInfo)->GetBlenderScene();
63 };
64
65
66 KX_LightObject::~KX_LightObject()
67 {
68         GPULamp *lamp;
69
70         if((lamp = GetGPULamp())) {
71                 float obmat[4][4] = {{0}};
72                 GPU_lamp_update(lamp, 0, obmat);
73         }
74
75         m_rendertools->RemoveLight(&m_lightobj);
76 }
77
78
79 CValue*         KX_LightObject::GetReplica()
80 {
81
82         KX_LightObject* replica = new KX_LightObject(*this);
83
84         // this will copy properties and so on...
85         CValue::AddDataToReplica(replica);
86
87         ProcessReplica(replica);
88         
89         replica->m_lightobj.m_worldmatrix = replica->GetOpenGLMatrixPtr();
90         m_rendertools->AddLight(&replica->m_lightobj);
91
92         return replica;
93 }
94
95 GPULamp *KX_LightObject::GetGPULamp()
96 {
97         if(m_glsl)
98                 return GPU_lamp_from_blender(m_blenderscene, GetBlenderObject(), GetBlenderGroupObject());
99         else
100                 return false;
101 }
102
103 void KX_LightObject::Update()
104 {
105         GPULamp *lamp;
106
107         if((lamp = GetGPULamp())) {
108                 float obmat[4][4];
109                 double *dobmat = GetOpenGLMatrixPtr()->getPointer();
110
111                 for(int i=0; i<4; i++)
112                         for(int j=0; j<4; j++, dobmat++)
113                                 obmat[i][j] = (float)*dobmat;
114
115                 GPU_lamp_update(lamp, m_lightobj.m_layer, obmat);
116         }
117 }
118
119 bool KX_LightObject::HasShadowBuffer()
120 {
121         GPULamp *lamp;
122
123         if((lamp = GetGPULamp()))
124                 return GPU_lamp_has_shadow_buffer(lamp);
125         else
126                 return false;
127 }
128
129 int KX_LightObject::GetShadowLayer()
130 {
131         GPULamp *lamp;
132
133         if((lamp = GetGPULamp()))
134                 return GPU_lamp_shadow_layer(lamp);
135         else
136                 return 0;
137 }
138
139 void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_Transform& camtrans)
140 {
141         GPULamp *lamp;
142         float viewmat[4][4], winmat[4][4];
143         int winsize;
144
145         /* bind framebuffer */
146         lamp = GetGPULamp();
147         GPU_lamp_shadow_buffer_bind(lamp, viewmat, &winsize, winmat);
148
149         /* setup camera transformation */
150         MT_Matrix4x4 modelviewmat((float*)viewmat);
151         MT_Matrix4x4 projectionmat((float*)winmat);
152
153         MT_Transform trans = MT_Transform((float*)viewmat);
154         camtrans.invert(trans);
155
156         cam->SetModelviewMatrix(modelviewmat);
157         cam->SetProjectionMatrix(projectionmat);
158         
159         cam->NodeSetLocalPosition(camtrans.getOrigin());
160         cam->NodeSetLocalOrientation(camtrans.getBasis());
161         cam->NodeUpdateGS(0,true);
162
163         /* setup rasterizer transformations */
164         ras->SetProjectionMatrix(projectionmat);
165         ras->SetViewMatrix(modelviewmat, cam->NodeGetWorldPosition(),
166                 cam->GetCameraLocation(), cam->GetCameraOrientation());
167 }
168
169 void KX_LightObject::UnbindShadowBuffer(RAS_IRasterizer *ras)
170 {
171         GPULamp *lamp = GetGPULamp();
172         GPU_lamp_shadow_buffer_unbind(lamp);
173 }
174
175 PyObject* KX_LightObject::_getattr(const STR_String& attr)
176 {
177         if (attr == "layer")
178                 return PyInt_FromLong(m_lightobj.m_layer);
179         
180         if (attr == "energy")
181                 return PyFloat_FromDouble(m_lightobj.m_energy);
182         
183         if (attr == "distance")
184                 return PyFloat_FromDouble(m_lightobj.m_distance);
185         
186         if (attr == "colour" || attr == "color")
187                 return Py_BuildValue("[fff]", m_lightobj.m_red, m_lightobj.m_green, m_lightobj.m_blue);
188                 
189         if (attr == "lin_attenuation")
190                 return PyFloat_FromDouble(m_lightobj.m_att1);
191         
192         if (attr == "quad_attenuation")
193                 return PyFloat_FromDouble(m_lightobj.m_att2);
194         
195         if (attr == "spotsize")
196                 return PyFloat_FromDouble(m_lightobj.m_spotsize);
197         
198         if (attr == "spotblend")
199                 return PyFloat_FromDouble(m_lightobj.m_spotblend);
200                 
201         if (attr == "SPOT")
202                 return PyInt_FromLong(RAS_LightObject::LIGHT_SPOT);
203                 
204         if (attr == "SUN")
205                 return PyInt_FromLong(RAS_LightObject::LIGHT_SUN);
206         
207         if (attr == "NORMAL")
208                 return PyInt_FromLong(RAS_LightObject::LIGHT_NORMAL);
209         
210         if (attr == "type")
211                 return PyInt_FromLong(m_lightobj.m_type);
212                 
213         _getattr_up(KX_GameObject);
214 }
215
216 int       KX_LightObject::_setattr(const STR_String& attr, PyObject *pyvalue)
217 {
218         if (attr == "SPOT" || attr == "SUN" || attr == "NORMAL")
219         {
220                 PyErr_Format(PyExc_RuntimeError, "Attribute %s is read only.", attr.ReadPtr());
221                 return 1;
222         }
223         
224         if (PyInt_Check(pyvalue))
225         {
226                 int value = PyInt_AsLong(pyvalue);
227                 if (attr == "layer")
228                 {
229                         m_lightobj.m_layer = value;
230                         return 0;
231                 }
232                 
233                 if (attr == "type")
234                 {
235                         if (value >= RAS_LightObject::LIGHT_SPOT && value <= RAS_LightObject::LIGHT_NORMAL)
236                                 m_lightobj.m_type = (RAS_LightObject::LightType) value;
237                         return 0;
238                 }
239         }
240         
241         if (PyFloat_Check(pyvalue))
242         {
243                 float value = PyFloat_AsDouble(pyvalue);
244                 if (attr == "energy")
245                 {
246                         m_lightobj.m_energy = value;
247                         return 0;
248                 }
249         
250                 if (attr == "distance")
251                 {
252                         m_lightobj.m_distance = value;
253                         return 0;
254                 }
255                 
256                 if (attr == "lin_attenuation")
257                 {
258                         m_lightobj.m_att1 = value;
259                         return 0;
260                 }
261                 
262                 if (attr == "quad_attenuation")
263                 {
264                         m_lightobj.m_att2 = value;
265                         return 0;
266                 }
267                 
268                 if (attr == "spotsize")
269                 {
270                         m_lightobj.m_spotsize = value;
271                         return 0;
272                 }
273                 
274                 if (attr == "spotblend")
275                 {
276                         m_lightobj.m_spotblend = value;
277                         return 0;
278                 }
279         }
280
281         if (PySequence_Check(pyvalue))
282         {
283                 if (attr == "colour" || attr == "color")
284                 {
285                         MT_Vector3 color;
286                         if (PyVecTo(pyvalue, color))
287                         {
288                                 m_lightobj.m_red = color[0];
289                                 m_lightobj.m_green = color[1];
290                                 m_lightobj.m_blue = color[2];
291                                 return 0;
292                         }
293                         return 1;
294                 }
295         }
296         
297         return KX_GameObject::_setattr(attr, pyvalue);
298 }
299
300 PyMethodDef KX_LightObject::Methods[] = {
301         {NULL,NULL} //Sentinel
302 };
303
304 char KX_LightObject::doc[] = "Module KX_LightObject\n\n"
305 "Constants:\n"
306 "\tSPOT\n"
307 "\tSUN\n"
308 "\tNORMAL\n"
309 "Attributes:\n"
310 "\ttype -> SPOT, SUN or NORMAL\n"
311 "\t\tThe type of light.\n"
312 "\tlayer -> integer bit field.\n"
313 "\t\tThe layers this light applies to.\n"
314 "\tenergy -> float.\n"
315 "\t\tThe brightness of the light.\n"
316 "\tdistance -> float.\n"
317 "\t\tThe effect radius of the light.\n"
318 "\tcolour -> list [r, g, b].\n"
319 "\tcolor  -> list [r, g, b].\n"
320 "\t\tThe color of the light.\n"
321 "\tlin_attenuation -> float.\n"
322 "\t\tThe attenuation factor for the light.\n"
323 "\tspotsize -> float.\n"
324 "\t\tThe size of the spot.\n"
325 "\tspotblend -> float.\n"
326 "\t\tThe blend? of the spot.\n";
327
328 PyTypeObject KX_LightObject::Type = {
329         PyObject_HEAD_INIT(&PyType_Type)
330                 0,
331                 "KX_LightObject",
332                 sizeof(KX_LightObject),
333                 0,
334                 PyDestructor,
335                 0,
336                 __getattr,
337                 __setattr,
338                 0, //&MyPyCompare,
339                 __repr,
340                 0, //&cvalue_as_number,
341                 0,
342                 0,
343                 0,
344                 0, 0, 0, 0, 0, 0,
345                 doc
346 };
347
348 PyParentObject KX_LightObject::Parents[] = {
349         &KX_LightObject::Type,
350         &KX_GameObject::Type,
351                 &SCA_IObject::Type,
352                 &CValue::Type,
353                 NULL
354 };