Merge from trunk 16122-16307
[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 #ifdef BLENDER_GLSL
46 #include "GPU_material.h"
47 #endif
48  
49 KX_LightObject::KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,
50                                                            class RAS_IRenderTools* rendertools,
51                                                            const RAS_LightObject&       lightobj,
52                                                            struct GPULamp *gpulamp,
53                                                            PyTypeObject* T
54                                                            )
55  :
56         KX_GameObject(sgReplicationInfo,callbacks,T),
57                 m_rendertools(rendertools)
58 {
59         m_lightobj = lightobj;
60         m_lightobj.m_worldmatrix = GetOpenGLMatrixPtr();
61         m_rendertools->AddLight(&m_lightobj);
62         m_gpulamp = gpulamp;
63 };
64
65
66 KX_LightObject::~KX_LightObject()
67 {
68         m_rendertools->RemoveLight(&m_lightobj);
69 }
70
71
72 CValue*         KX_LightObject::GetReplica()
73 {
74
75         KX_LightObject* replica = new KX_LightObject(*this);
76         
77         // this will copy properties and so on...
78         CValue::AddDataToReplica(replica);
79
80         ProcessReplica(replica);
81         
82         replica->m_lightobj.m_worldmatrix = replica->GetOpenGLMatrixPtr();
83         m_rendertools->AddLight(&replica->m_lightobj);
84         return replica;
85 }
86
87 void KX_LightObject::Update()
88 {
89 #ifdef BLENDER_GLSL
90         if(m_gpulamp) {
91                 float obmat[4][4];
92                 double *dobmat = GetOpenGLMatrixPtr()->getPointer();
93
94                 for(int i=0; i<4; i++)
95                         for(int j=0; j<4; j++, dobmat++)
96                                 obmat[i][j] = (float)*dobmat;
97
98                 GPU_lamp_update(m_gpulamp, obmat);
99         }
100 #endif
101 }
102
103 bool KX_LightObject::HasShadowBuffer()
104 {
105 #ifdef BLENDER_GLSL
106         return (m_gpulamp && GPU_lamp_has_shadow_buffer(m_gpulamp));
107 #else
108         return false;
109 #endif
110 }
111
112 int KX_LightObject::GetShadowLayer()
113 {
114 #ifdef BLENDER_GLSL
115         if(m_gpulamp)
116                 return GPU_lamp_shadow_layer(m_gpulamp);
117         else
118 #endif
119                 return 0;
120 }
121
122 void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_Transform& camtrans)
123 {
124 #ifdef BLENDER_GLSL
125         float viewmat[4][4], winmat[4][4];
126         int winsize;
127
128         /* bind framebuffer */
129         GPU_lamp_shadow_buffer_bind(m_gpulamp, viewmat, &winsize, winmat);
130
131         /* setup camera transformation */
132         MT_Matrix4x4 modelviewmat((float*)viewmat);
133         MT_Matrix4x4 projectionmat((float*)winmat);
134
135         MT_Transform trans = MT_Transform((float*)viewmat);
136         camtrans.invert(trans);
137
138         cam->SetModelviewMatrix(modelviewmat);
139         cam->SetProjectionMatrix(projectionmat);
140         
141         cam->NodeSetLocalPosition(camtrans.getOrigin());
142         cam->NodeSetLocalOrientation(camtrans.getBasis());
143         cam->NodeUpdateGS(0,true);
144
145         /* setup rasterizer transformations */
146         ras->SetProjectionMatrix(projectionmat);
147         ras->SetViewMatrix(modelviewmat, cam->NodeGetWorldPosition(),
148                 cam->GetCameraLocation(), cam->GetCameraOrientation());
149 #endif
150 }
151
152 void KX_LightObject::UnbindShadowBuffer(RAS_IRasterizer *ras)
153 {
154 #ifdef BLENDER_GLSL
155         GPU_lamp_shadow_buffer_unbind(m_gpulamp);
156 #endif
157 }
158
159 PyObject* KX_LightObject::_getattr(const STR_String& attr)
160 {
161         if (attr == "layer")
162                 return PyInt_FromLong(m_lightobj.m_layer);
163         
164         if (attr == "energy")
165                 return PyFloat_FromDouble(m_lightobj.m_energy);
166         
167         if (attr == "distance")
168                 return PyFloat_FromDouble(m_lightobj.m_distance);
169         
170         if (attr == "colour" || attr == "color")
171                 return Py_BuildValue("[fff]", m_lightobj.m_red, m_lightobj.m_green, m_lightobj.m_blue);
172                 
173         if (attr == "lin_attenuation")
174                 return PyFloat_FromDouble(m_lightobj.m_att1);
175         
176         if (attr == "quad_attenuation")
177                 return PyFloat_FromDouble(m_lightobj.m_att2);
178         
179         if (attr == "spotsize")
180                 return PyFloat_FromDouble(m_lightobj.m_spotsize);
181         
182         if (attr == "spotblend")
183                 return PyFloat_FromDouble(m_lightobj.m_spotblend);
184                 
185         if (attr == "SPOT")
186                 return PyInt_FromLong(RAS_LightObject::LIGHT_SPOT);
187                 
188         if (attr == "SUN")
189                 return PyInt_FromLong(RAS_LightObject::LIGHT_SUN);
190         
191         if (attr == "NORMAL")
192                 return PyInt_FromLong(RAS_LightObject::LIGHT_NORMAL);
193         
194         if (attr == "type")
195                 return PyInt_FromLong(m_lightobj.m_type);
196                 
197         _getattr_up(KX_GameObject);
198 }
199
200 int       KX_LightObject::_setattr(const STR_String& attr, PyObject *pyvalue)
201 {
202         if (attr == "SPOT" || attr == "SUN" || attr == "NORMAL")
203         {
204                 PyErr_Format(PyExc_RuntimeError, "Attribute %s is read only.", attr.ReadPtr());
205                 return 1;
206         }
207         
208         if (PyInt_Check(pyvalue))
209         {
210                 int value = PyInt_AsLong(pyvalue);
211                 if (attr == "layer")
212                 {
213                         m_lightobj.m_layer = value;
214                         return 0;
215                 }
216                 
217                 if (attr == "type")
218                 {
219                         if (value >= RAS_LightObject::LIGHT_SPOT && value <= RAS_LightObject::LIGHT_NORMAL)
220                                 m_lightobj.m_type = (RAS_LightObject::LightType) value;
221                         return 0;
222                 }
223         }
224         
225         if (PyFloat_Check(pyvalue))
226         {
227                 float value = PyFloat_AsDouble(pyvalue);
228                 if (attr == "energy")
229                 {
230                         m_lightobj.m_energy = value;
231                         return 0;
232                 }
233         
234                 if (attr == "distance")
235                 {
236                         m_lightobj.m_distance = value;
237                         return 0;
238                 }
239                 
240                 if (attr == "lin_attenuation")
241                 {
242                         m_lightobj.m_att1 = value;
243                         return 0;
244                 }
245                 
246                 if (attr == "quad_attenuation")
247                 {
248                         m_lightobj.m_att2 = value;
249                         return 0;
250                 }
251                 
252                 if (attr == "spotsize")
253                 {
254                         m_lightobj.m_spotsize = value;
255                         return 0;
256                 }
257                 
258                 if (attr == "spotblend")
259                 {
260                         m_lightobj.m_spotblend = value;
261                         return 0;
262                 }
263         }
264
265         if (PySequence_Check(pyvalue))
266         {
267                 if (attr == "colour" || attr == "color")
268                 {
269                         MT_Vector3 color;
270                         if (PyVecTo(pyvalue, color))
271                         {
272                                 m_lightobj.m_red = color[0];
273                                 m_lightobj.m_green = color[1];
274                                 m_lightobj.m_blue = color[2];
275                                 return 0;
276                         }
277                         return 1;
278                 }
279         }
280         
281         return KX_GameObject::_setattr(attr, pyvalue);
282 }
283
284 PyMethodDef KX_LightObject::Methods[] = {
285         {NULL,NULL} //Sentinel
286 };
287
288 char KX_LightObject::doc[] = "Module KX_LightObject\n\n"
289 "Constants:\n"
290 "\tSPOT\n"
291 "\tSUN\n"
292 "\tNORMAL\n"
293 "Attributes:\n"
294 "\ttype -> SPOT, SUN or NORMAL\n"
295 "\t\tThe type of light.\n"
296 "\tlayer -> integer bit field.\n"
297 "\t\tThe layers this light applies to.\n"
298 "\tenergy -> float.\n"
299 "\t\tThe brightness of the light.\n"
300 "\tdistance -> float.\n"
301 "\t\tThe effect radius of the light.\n"
302 "\tcolour -> list [r, g, b].\n"
303 "\tcolor  -> list [r, g, b].\n"
304 "\t\tThe color of the light.\n"
305 "\tlin_attenuation -> float.\n"
306 "\t\tThe attenuation factor for the light.\n"
307 "\tspotsize -> float.\n"
308 "\t\tThe size of the spot.\n"
309 "\tspotblend -> float.\n"
310 "\t\tThe blend? of the spot.\n";
311
312 PyTypeObject KX_LightObject::Type = {
313         PyObject_HEAD_INIT(&PyType_Type)
314                 0,
315                 "KX_LightObject",
316                 sizeof(KX_LightObject),
317                 0,
318                 PyDestructor,
319                 0,
320                 __getattr,
321                 __setattr,
322                 0, //&MyPyCompare,
323                 __repr,
324                 0, //&cvalue_as_number,
325                 0,
326                 0,
327                 0,
328                 0, 0, 0, 0, 0, 0,
329                 doc
330 };
331
332 PyParentObject KX_LightObject::Parents[] = {
333         &KX_LightObject::Type,
334         &KX_GameObject::Type,
335                 &SCA_IObject::Type,
336                 &CValue::Type,
337                 NULL
338 };