fe575384a35acb76f4b4042755b7f71150313232
[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         replica->ProcessReplica();
86         
87         replica->m_lightobj.m_worldmatrix = replica->GetOpenGLMatrixPtr();
88         m_rendertools->AddLight(&replica->m_lightobj);
89
90         return replica;
91 }
92
93 GPULamp *KX_LightObject::GetGPULamp()
94 {
95         if(m_glsl)
96                 return GPU_lamp_from_blender(m_blenderscene, GetBlenderObject(), GetBlenderGroupObject());
97         else
98                 return false;
99 }
100
101 void KX_LightObject::Update()
102 {
103         GPULamp *lamp;
104
105         if((lamp = GetGPULamp()) != NULL && GetSGNode()) {
106                 float obmat[4][4];
107                 // lights don't get their openGL matrix updated, do it now
108                 if (GetSGNode()->IsDirty())
109                         GetOpenGLMatrix();
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                 GPU_lamp_update_colors(lamp, m_lightobj.m_red, m_lightobj.m_green, 
118                         m_lightobj.m_blue, m_lightobj.m_energy);
119         }
120 }
121
122 bool KX_LightObject::HasShadowBuffer()
123 {
124         GPULamp *lamp;
125
126         if((lamp = GetGPULamp()))
127                 return GPU_lamp_has_shadow_buffer(lamp);
128         else
129                 return false;
130 }
131
132 int KX_LightObject::GetShadowLayer()
133 {
134         GPULamp *lamp;
135
136         if((lamp = GetGPULamp()))
137                 return GPU_lamp_shadow_layer(lamp);
138         else
139                 return 0;
140 }
141
142 void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_Transform& camtrans)
143 {
144         GPULamp *lamp;
145         float viewmat[4][4], winmat[4][4];
146         int winsize;
147
148         /* bind framebuffer */
149         lamp = GetGPULamp();
150         GPU_lamp_shadow_buffer_bind(lamp, viewmat, &winsize, winmat);
151
152         /* setup camera transformation */
153         MT_Matrix4x4 modelviewmat((float*)viewmat);
154         MT_Matrix4x4 projectionmat((float*)winmat);
155
156         MT_Transform trans = MT_Transform((float*)viewmat);
157         camtrans.invert(trans);
158
159         cam->SetModelviewMatrix(modelviewmat);
160         cam->SetProjectionMatrix(projectionmat);
161         
162         cam->NodeSetLocalPosition(camtrans.getOrigin());
163         cam->NodeSetLocalOrientation(camtrans.getBasis());
164         cam->NodeUpdateGS(0);
165
166         /* setup rasterizer transformations */
167         ras->SetProjectionMatrix(projectionmat);
168         ras->SetViewMatrix(modelviewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective);
169 }
170
171 void KX_LightObject::UnbindShadowBuffer(RAS_IRasterizer *ras)
172 {
173         GPULamp *lamp = GetGPULamp();
174         GPU_lamp_shadow_buffer_unbind(lamp);
175 }
176
177 /* ------------------------------------------------------------------------- */
178 /* Python Integration Hooks                                                                      */
179 /* ------------------------------------------------------------------------- */
180
181 PyObject* KX_LightObject::py_getattro_dict() {
182         py_getattro_dict_up(KX_GameObject);
183 }
184
185
186 PyTypeObject KX_LightObject::Type = {
187 #if (PY_VERSION_HEX >= 0x02060000)
188         PyVarObject_HEAD_INIT(NULL, 0)
189 #else
190         /* python 2.5 and below */
191         PyObject_HEAD_INIT( NULL )  /* required py macro */
192         0,                          /* ob_size */
193 #endif
194                 "KX_LightObject",
195                 sizeof(PyObjectPlus_Proxy),
196                 0,
197                 py_base_dealloc,
198                 0,
199                 0,
200                 0,
201                 0,
202                 py_base_repr,
203                 0,0,
204                 &KX_GameObject::Mapping,
205                 0,0,0,
206                 py_base_getattro,
207                 py_base_setattro,
208                 0,0,0,0,0,0,0,0,0,
209                 Methods
210 };
211
212 PyParentObject KX_LightObject::Parents[] = {
213         &KX_LightObject::Type,
214         &KX_GameObject::Type,
215                 &SCA_IObject::Type,
216                 &CValue::Type,
217                 NULL
218 };
219
220 PyMethodDef KX_LightObject::Methods[] = {
221         {NULL,NULL} //Sentinel
222 };
223
224 PyAttributeDef KX_LightObject::Attributes[] = {
225         KX_PYATTRIBUTE_INT_RW("layer", 1, 20, true, KX_LightObject, m_lightobj.m_layer),
226         KX_PYATTRIBUTE_FLOAT_RW("energy", 0, 10, KX_LightObject, m_lightobj.m_energy),
227         KX_PYATTRIBUTE_FLOAT_RW("distance", 0.01, 5000, KX_LightObject, m_lightobj.m_distance),
228         KX_PYATTRIBUTE_RW_FUNCTION("color", KX_LightObject, pyattr_get_color, pyattr_set_color),
229         KX_PYATTRIBUTE_RW_FUNCTION("colour", KX_LightObject, pyattr_get_color, pyattr_set_color),
230         KX_PYATTRIBUTE_FLOAT_RW("lin_attenuation", 0, 1, KX_LightObject, m_lightobj.m_att1),
231         KX_PYATTRIBUTE_FLOAT_RW("quad_attenuation", 0, 1, KX_LightObject, m_lightobj.m_att2),
232         KX_PYATTRIBUTE_FLOAT_RW("spotsize", 1, 180, KX_LightObject, m_lightobj.m_spotsize),
233         KX_PYATTRIBUTE_FLOAT_RW("spotblend", 0, 1, KX_LightObject, m_lightobj.m_spotblend),
234         KX_PYATTRIBUTE_RO_FUNCTION("SPOT", KX_LightObject, pyattr_get_typeconst),
235         KX_PYATTRIBUTE_RO_FUNCTION("SUN", KX_LightObject, pyattr_get_typeconst),
236         KX_PYATTRIBUTE_RO_FUNCTION("NORMAL", KX_LightObject, pyattr_get_typeconst),
237         KX_PYATTRIBUTE_RW_FUNCTION("type", KX_LightObject, pyattr_get_type, pyattr_set_type),
238         { NULL }        //Sentinel
239 };
240
241 PyObject* KX_LightObject::pyattr_get_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
242 {
243         KX_LightObject* self = static_cast<KX_LightObject*>(self_v);
244         return Py_BuildValue("[fff]", self->m_lightobj.m_red, self->m_lightobj.m_green, self->m_lightobj.m_blue);
245 }
246
247 int KX_LightObject::pyattr_set_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
248 {
249         KX_LightObject* self = static_cast<KX_LightObject*>(self_v);
250
251         MT_Vector3 color;
252         if (PyVecTo(value, color))
253         {
254                 self->m_lightobj.m_red = color[0];
255                 self->m_lightobj.m_green = color[1];
256                 self->m_lightobj.m_blue = color[2];
257                 return PY_SET_ATTR_SUCCESS;
258         }
259         return PY_SET_ATTR_FAIL;
260 }
261
262 PyObject* KX_LightObject::pyattr_get_typeconst(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
263 {
264         PyObject* retvalue;
265
266         const char* type = attrdef->m_name;
267
268         if(strcmp(type, "SPOT")) {
269                 retvalue = PyInt_FromLong(RAS_LightObject::LIGHT_SPOT);
270         } else if (strcmp(type, "SUN")) {
271                 retvalue = PyInt_FromLong(RAS_LightObject::LIGHT_SUN);
272         } else if (strcmp(type, "NORMAL")) {
273                 retvalue = PyInt_FromLong(RAS_LightObject::LIGHT_NORMAL);
274         }
275
276         return retvalue;
277 }
278
279 PyObject* KX_LightObject::pyattr_get_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef)
280 {
281         KX_LightObject* self = static_cast<KX_LightObject*>(self_v);
282         return PyInt_FromLong(self->m_lightobj.m_type);
283 }
284
285 int KX_LightObject::pyattr_set_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject* value)
286 {
287         KX_LightObject* self = static_cast<KX_LightObject*>(self_v);
288         int val = PyInt_AsLong(value);
289         if((val==-1 && PyErr_Occurred()) || val<0 || val>2) {
290                 PyErr_SetString(PyExc_ValueError, "light.type= val: KX_LightObject, expected an int between 0 and 2");
291                 return PY_SET_ATTR_FAIL;
292         }
293         
294         switch(val) {
295                 case 0:
296                         self->m_lightobj.m_type = self->m_lightobj.LIGHT_SPOT;
297                         break;
298                 case 1:
299                         self->m_lightobj.m_type = self->m_lightobj.LIGHT_SUN;
300                         break;
301                 case 2:
302                         self->m_lightobj.m_type = self->m_lightobj.LIGHT_NORMAL;
303                         break;
304         }
305
306         return PY_SET_ATTR_SUCCESS;
307 }
308
309
310 PyObject* KX_LightObject::py_getattro(PyObject *attr)
311 {
312         py_getattro_up(KX_GameObject);
313 }
314
315 int KX_LightObject::py_setattro(PyObject *attr, PyObject *value)
316 {
317         py_setattro_up(KX_GameObject);
318 }