f996f86d751239d1d966093c4a8972d51cfb085a
[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_lightobj.m_scene = sgReplicationInfo;
61         m_rendertools->AddLight(&m_lightobj);
62         m_glsl = glsl;
63         m_blenderscene = ((KX_Scene*)sgReplicationInfo)->GetBlenderScene();
64 };
65
66
67 KX_LightObject::~KX_LightObject()
68 {
69         GPULamp *lamp;
70
71         if((lamp = GetGPULamp())) {
72                 float obmat[4][4] = {{0}};
73                 GPU_lamp_update(lamp, 0, obmat);
74         }
75
76         m_rendertools->RemoveLight(&m_lightobj);
77 }
78
79
80 CValue*         KX_LightObject::GetReplica()
81 {
82
83         KX_LightObject* replica = new KX_LightObject(*this);
84
85         // this will copy properties and so on...
86         CValue::AddDataToReplica(replica);
87
88         ProcessReplica(replica);
89         
90         replica->m_lightobj.m_worldmatrix = replica->GetOpenGLMatrixPtr();
91         m_rendertools->AddLight(&replica->m_lightobj);
92
93         return replica;
94 }
95
96 GPULamp *KX_LightObject::GetGPULamp()
97 {
98         if(m_glsl)
99                 return GPU_lamp_from_blender(m_blenderscene, GetBlenderObject(), GetBlenderGroupObject());
100         else
101                 return false;
102 }
103
104 void KX_LightObject::Update()
105 {
106         GPULamp *lamp;
107
108         if((lamp = GetGPULamp())) {
109                 float obmat[4][4];
110                 double *dobmat = GetOpenGLMatrixPtr()->getPointer();
111
112                 for(int i=0; i<4; i++)
113                         for(int j=0; j<4; j++, dobmat++)
114                                 obmat[i][j] = (float)*dobmat;
115
116                 GPU_lamp_update(lamp, m_lightobj.m_layer, obmat);
117         }
118 }
119
120 bool KX_LightObject::HasShadowBuffer()
121 {
122         GPULamp *lamp;
123
124         if((lamp = GetGPULamp()))
125                 return GPU_lamp_has_shadow_buffer(lamp);
126         else
127                 return false;
128 }
129
130 int KX_LightObject::GetShadowLayer()
131 {
132         GPULamp *lamp;
133
134         if((lamp = GetGPULamp()))
135                 return GPU_lamp_shadow_layer(lamp);
136         else
137                 return 0;
138 }
139
140 void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_Transform& camtrans)
141 {
142         GPULamp *lamp;
143         float viewmat[4][4], winmat[4][4];
144         int winsize;
145
146         /* bind framebuffer */
147         lamp = GetGPULamp();
148         GPU_lamp_shadow_buffer_bind(lamp, viewmat, &winsize, winmat);
149
150         /* setup camera transformation */
151         MT_Matrix4x4 modelviewmat((float*)viewmat);
152         MT_Matrix4x4 projectionmat((float*)winmat);
153
154         MT_Transform trans = MT_Transform((float*)viewmat);
155         camtrans.invert(trans);
156
157         cam->SetModelviewMatrix(modelviewmat);
158         cam->SetProjectionMatrix(projectionmat);
159         
160         cam->NodeSetLocalPosition(camtrans.getOrigin());
161         cam->NodeSetLocalOrientation(camtrans.getBasis());
162         cam->NodeUpdateGS(0);
163
164         /* setup rasterizer transformations */
165         ras->SetProjectionMatrix(projectionmat);
166         ras->SetViewMatrix(modelviewmat, cam->NodeGetWorldPosition(),
167                 cam->GetCameraLocation(), cam->GetCameraOrientation());
168 }
169
170 void KX_LightObject::UnbindShadowBuffer(RAS_IRasterizer *ras)
171 {
172         GPULamp *lamp = GetGPULamp();
173         GPU_lamp_shadow_buffer_unbind(lamp);
174 }
175
176 PyObject* KX_LightObject::py_getattro(PyObject *attr)
177 {
178         char *attr_str= PyString_AsString(attr);
179         
180         if (!strcmp(attr_str, "layer"))
181                 return PyInt_FromLong(m_lightobj.m_layer);
182         
183         if (!strcmp(attr_str, "energy"))
184                 return PyFloat_FromDouble(m_lightobj.m_energy);
185         
186         if (!strcmp(attr_str, "distance"))
187                 return PyFloat_FromDouble(m_lightobj.m_distance);
188         
189         if (!strcmp(attr_str, "colour") || !strcmp(attr_str, "color"))
190                 return Py_BuildValue("[fff]", m_lightobj.m_red, m_lightobj.m_green, m_lightobj.m_blue);
191                 
192         if (!strcmp(attr_str, "lin_attenuation"))
193                 return PyFloat_FromDouble(m_lightobj.m_att1);
194         
195         if (!strcmp(attr_str, "quad_attenuation"))
196                 return PyFloat_FromDouble(m_lightobj.m_att2);
197         
198         if (!strcmp(attr_str, "spotsize"))
199                 return PyFloat_FromDouble(m_lightobj.m_spotsize);
200         
201         if (!strcmp(attr_str, "spotblend"))
202                 return PyFloat_FromDouble(m_lightobj.m_spotblend);
203                 
204         if (!strcmp(attr_str, "SPOT"))
205                 return PyInt_FromLong(RAS_LightObject::LIGHT_SPOT);
206                 
207         if (!strcmp(attr_str, "SUN"))
208                 return PyInt_FromLong(RAS_LightObject::LIGHT_SUN);
209         
210         if (!strcmp(attr_str, "NORMAL"))
211                 return PyInt_FromLong(RAS_LightObject::LIGHT_NORMAL);
212         
213         if (!strcmp(attr_str, "type"))
214                 return PyInt_FromLong(m_lightobj.m_type);
215                 
216         py_getattro_up(KX_GameObject);
217 }
218
219 int       KX_LightObject::py_setattro(PyObject *attr, PyObject *pyvalue)
220 {
221         char *attr_str= PyString_AsString(attr);
222         if (PyInt_Check(pyvalue))
223         {
224                 int value = PyInt_AsLong(pyvalue);
225                 if (!strcmp(attr_str, "layer"))
226                 {
227                         m_lightobj.m_layer = value;
228                         return 0;
229                 }
230                 
231                 if (!strcmp(attr_str, "type"))
232                 {
233                         if (value >= RAS_LightObject::LIGHT_SPOT && value <= RAS_LightObject::LIGHT_NORMAL)
234                                 m_lightobj.m_type = (RAS_LightObject::LightType) value;
235                         return 0;
236                 }
237         }
238         
239         if (PyFloat_Check(pyvalue) || PyInt_Check(pyvalue))
240         {
241                 float value = PyFloat_AsDouble(pyvalue);
242                 if (!strcmp(attr_str, "energy"))
243                 {
244                         m_lightobj.m_energy = value;
245                         return 0;
246                 }
247         
248                 if (!strcmp(attr_str, "distance"))
249                 {
250                         m_lightobj.m_distance = value;
251                         return 0;
252                 }
253                 
254                 if (!strcmp(attr_str, "lin_attenuation"))
255                 {
256                         m_lightobj.m_att1 = value;
257                         return 0;
258                 }
259                 
260                 if (!strcmp(attr_str, "quad_attenuation"))
261                 {
262                         m_lightobj.m_att2 = value;
263                         return 0;
264                 }
265                 
266                 if (!strcmp(attr_str, "spotsize"))
267                 {
268                         m_lightobj.m_spotsize = value;
269                         return 0;
270                 }
271                 
272                 if (!strcmp(attr_str, "spotblend"))
273                 {
274                         m_lightobj.m_spotblend = value;
275                         return 0;
276                 }
277         }
278
279         if (PySequence_Check(pyvalue))
280         {
281                 if (!strcmp(attr_str, "colour") || !strcmp(attr_str, "color"))
282                 {
283                         MT_Vector3 color;
284                         if (PyVecTo(pyvalue, color))
285                         {
286                                 m_lightobj.m_red = color[0];
287                                 m_lightobj.m_green = color[1];
288                                 m_lightobj.m_blue = color[2];
289                                 return 0;
290                         }
291                         return 1;
292                 }
293         }
294         
295         if (!strcmp(attr_str, "SPOT") || !strcmp(attr_str, "SUN") || !strcmp(attr_str, "NORMAL"))
296         {
297                 PyErr_Format(PyExc_RuntimeError, "Attribute %s is read only.", attr_str);
298                 return 1;
299         }
300         
301         return KX_GameObject::py_setattro(attr, pyvalue);
302 }
303
304 PyMethodDef KX_LightObject::Methods[] = {
305         {NULL,NULL} //Sentinel
306 };
307
308 PyAttributeDef KX_LightObject::Attributes[] = {
309         KX_PYATTRIBUTE_DUMMY("layer"),
310         KX_PYATTRIBUTE_DUMMY("energy"),
311         KX_PYATTRIBUTE_DUMMY("distance"),
312         KX_PYATTRIBUTE_DUMMY("colour"),
313         KX_PYATTRIBUTE_DUMMY("color"),
314         KX_PYATTRIBUTE_DUMMY("lin_attenuation"),
315         KX_PYATTRIBUTE_DUMMY("quad_attenuation"),
316         KX_PYATTRIBUTE_DUMMY("spotsize"),
317         KX_PYATTRIBUTE_DUMMY("spotblend"),
318         KX_PYATTRIBUTE_DUMMY("SPOT"),
319         KX_PYATTRIBUTE_DUMMY("SUN"),
320         KX_PYATTRIBUTE_DUMMY("NORMAL"),
321         KX_PYATTRIBUTE_DUMMY("type"),
322         { NULL }        //Sentinel
323 };
324
325 PyTypeObject KX_LightObject::Type = {
326         PyObject_HEAD_INIT(NULL)
327                 0,
328                 "KX_LightObject",
329                 sizeof(KX_LightObject),
330                 0,
331                 PyDestructor,
332                 0,
333                 0,
334                 0,
335                 0,
336                 py_base_repr,
337                 0,0,0,0,0,0,
338                 py_base_getattro,
339                 py_base_setattro,
340                 0,0,0,0,0,0,0,0,0,
341                 Methods
342 };
343
344 PyParentObject KX_LightObject::Parents[] = {
345         &KX_LightObject::Type,
346         &KX_GameObject::Type,
347                 &SCA_IObject::Type,
348                 &CValue::Type,
349                 NULL
350 };