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