Make materials use PyAttributeDef's
[blender.git] / source / gameengine / Ketsji / KX_PolygonMaterial.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 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31
32 #include "KX_PolygonMaterial.h"
33
34 #include "BKE_mesh.h"
35 #include "BKE_global.h"
36 #include "BKE_image.h"
37
38 #include "DNA_material_types.h"
39 #include "DNA_texture_types.h"
40 #include "DNA_image_types.h"
41 #include "DNA_meshdata_types.h"
42
43 #include "IMB_imbuf_types.h"
44
45 #include "GPU_draw.h"
46
47 #include "MEM_guardedalloc.h"
48
49 #include "RAS_LightObject.h"
50 #include "RAS_MaterialBucket.h"
51
52 #include "KX_PyMath.h"
53
54 KX_PolygonMaterial::KX_PolygonMaterial(const STR_String &texname,
55                                                                                            Material *material,
56                                                                                            int tile,
57                                                                                            int tilexrep,
58                                                                                            int tileyrep,
59                                                                                            int mode,
60                                                                                            int transp,
61                                                                                            bool alpha,
62                                                                                            bool zsort,
63                                                                                            int lightlayer,
64                                                                                            struct MTFace* tface,
65                                                                                            unsigned int* mcol,
66                                                                                            PyTypeObject *T)
67                 : PyObjectPlus(T),
68                   RAS_IPolyMaterial(texname,
69                                                         STR_String(material?material->id.name:""),
70                                                         tile,
71                                                         tilexrep,
72                                                         tileyrep,
73                                                         mode,
74                                                         transp,
75                                                         alpha,
76                                                         zsort,
77                                                         lightlayer),
78                 m_tface(tface),
79                 m_mcol(mcol),
80                 m_material(material),
81                 m_pymaterial(0),
82                 m_pass(0)
83 {
84 }
85
86 KX_PolygonMaterial::~KX_PolygonMaterial()
87 {
88         if (m_pymaterial)
89         {
90                 Py_DECREF(m_pymaterial);
91         }
92 }
93
94 bool KX_PolygonMaterial::Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const 
95 {
96         bool dopass = false;
97         if (m_pymaterial)
98         {
99                 PyObject *pyRasty = PyCObject_FromVoidPtr((void*)rasty, NULL);  /* new reference */
100                 PyObject *pyCachingInfo = PyCObject_FromVoidPtr((void*) &cachingInfo, NULL); /* new reference */
101                 
102                 PyObject *ret = PyObject_CallMethod(m_pymaterial, "activate", "(NNO)", pyRasty, pyCachingInfo, (PyObject*) this);
103                 if (ret)
104                 {
105                         bool value = PyInt_AsLong(ret);
106                         Py_DECREF(ret);
107                         dopass = value;
108                 }
109                 else
110                 {
111                         PyErr_Print();
112                 }
113         }
114         else
115         {
116                 switch (m_pass++)
117                 {
118                         case 0:
119                                 DefaultActivate(rasty, cachingInfo);
120                                 dopass = true;
121                                 break;
122                         default:
123                                 m_pass = 0;
124                                 dopass = false;
125                                 break;
126                 }
127         }
128         
129         return dopass;
130 }
131
132 void KX_PolygonMaterial::DefaultActivate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const 
133 {
134         if (GetCachingInfo() != cachingInfo)
135         {
136                 if (!cachingInfo)
137                         GPU_set_tpage(NULL);
138
139                 cachingInfo = GetCachingInfo();
140
141                 if ((m_drawingmode & 4)&& (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED))
142                 {
143                         Image *ima = (Image*)m_tface->tpage;
144                         GPU_update_image_time(ima, rasty->GetTime());
145                         GPU_set_tpage(m_tface);
146                 }
147                 else
148                         GPU_set_tpage(NULL);
149                 
150                 if(m_drawingmode & RAS_IRasterizer::KX_TWOSIDE)
151                         rasty->SetCullFace(false);
152                 else
153                         rasty->SetCullFace(true);
154
155                 if ((m_drawingmode & RAS_IRasterizer::KX_LINES) ||
156                     (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME))
157                         rasty->SetLines(true);
158                 else
159                         rasty->SetLines(false);
160         }
161
162         rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity);
163         rasty->SetShinyness(m_shininess);
164         rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0);
165         if (m_material)
166                 rasty->SetPolygonOffset(-m_material->zoffs, 0.0);
167 }
168
169 //----------------------------------------------------------------------------
170 //Python
171
172
173 PyMethodDef KX_PolygonMaterial::Methods[] = {
174         KX_PYMETHODTABLE(KX_PolygonMaterial, setCustomMaterial),
175         KX_PYMETHODTABLE(KX_PolygonMaterial, updateTexture),
176         KX_PYMETHODTABLE(KX_PolygonMaterial, setTexture),
177         KX_PYMETHODTABLE(KX_PolygonMaterial, activate),
178 //      KX_PYMETHODTABLE(KX_PolygonMaterial, setPerPixelLights),
179         
180         {NULL,NULL} //Sentinel
181 };
182
183 PyAttributeDef KX_PolygonMaterial::Attributes[] = {
184         KX_PYATTRIBUTE_RO_FUNCTION("texture",   KX_PolygonMaterial, pyattr_get_texture),
185         KX_PYATTRIBUTE_RO_FUNCTION("material",  KX_PolygonMaterial, pyattr_get_material), /* should probably be .name ? */
186         
187         KX_PYATTRIBUTE_INT_RW("tile", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_tile),
188         KX_PYATTRIBUTE_INT_RW("tilexrep", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_tilexrep),
189         KX_PYATTRIBUTE_INT_RW("tileyrep", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_tileyrep),
190         KX_PYATTRIBUTE_INT_RW("drawingmode", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_drawingmode),        
191         KX_PYATTRIBUTE_INT_RW("lightlayer", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_lightlayer),
192
193         KX_PYATTRIBUTE_BOOL_RW("transparent", KX_PolygonMaterial, m_alpha),
194         KX_PYATTRIBUTE_BOOL_RW("zsort", KX_PolygonMaterial, m_zsort),
195         
196         KX_PYATTRIBUTE_FLOAT_RW("shininess", 0.0f, 1000.0f, KX_PolygonMaterial, m_shininess),
197         KX_PYATTRIBUTE_FLOAT_RW("specularity", 0.0f, 1000.0f, KX_PolygonMaterial, m_specularity),
198         
199         KX_PYATTRIBUTE_RW_FUNCTION("diffuse", KX_PolygonMaterial, pyattr_get_texture, pyattr_set_diffuse),
200         KX_PYATTRIBUTE_RW_FUNCTION("specular",KX_PolygonMaterial, pyattr_get_specular, pyattr_set_specular),    
201         
202         KX_PYATTRIBUTE_RO_FUNCTION("tface",     KX_PolygonMaterial, pyattr_get_tface), /* How the heck is this even useful??? - Campbell */
203         KX_PYATTRIBUTE_RO_FUNCTION("gl_texture", KX_PolygonMaterial, pyattr_get_gl_texture), /* could be called 'bindcode' */
204         
205         /* triangle used to be an attribute, removed for 2.49, nobody should be using it */
206         { NULL }        //Sentinel
207 };
208
209 PyTypeObject KX_PolygonMaterial::Type = {
210         PyObject_HEAD_INIT(NULL)
211                 0,
212                 "KX_PolygonMaterial",
213                 sizeof(KX_PolygonMaterial),
214                 0,
215                 PyDestructor,
216                 0,
217                 0,
218                 0,
219                 0,
220                 py_base_repr,
221                 0,0,0,0,0,0,
222                 py_base_getattro,
223                 py_base_setattro,
224                 0,0,0,0,0,0,0,0,0,
225                 Methods
226 };
227
228 PyParentObject KX_PolygonMaterial::Parents[] = {
229         &KX_PolygonMaterial::Type,
230         &PyObjectPlus::Type,
231         NULL
232 };
233
234 PyObject* KX_PolygonMaterial::py_getattro(PyObject *attr)
235 {
236         PyObject* object = py_getattro_self(Attributes, this, attr);
237         if (object != NULL)
238                 return object;
239         
240         py_getattro_up(PyObjectPlus);
241 }
242
243 int KX_PolygonMaterial::py_setattro(PyObject *attr, PyObject *value)
244 {
245         int ret = py_setattro_self(Attributes, this, attr, value);
246         if (ret >= 0)
247                 return ret;
248
249         return PyObjectPlus::py_setattro(attr, value);
250 }
251
252 KX_PYMETHODDEF_DOC(KX_PolygonMaterial, setCustomMaterial, "setCustomMaterial(material)")
253 {
254         PyObject *material;
255         if (PyArg_ParseTuple(args, "O", &material))
256         {
257                 if (m_pymaterial) {
258                         Py_DECREF(m_pymaterial);
259                 }
260                 m_pymaterial = material;
261                 Py_INCREF(m_pymaterial);
262                 Py_RETURN_NONE;
263         }
264         
265         return NULL;
266 }
267
268 KX_PYMETHODDEF_DOC(KX_PolygonMaterial, updateTexture, "updateTexture(tface, rasty)")
269 {
270         PyObject *pyrasty, *pytface;
271         if (PyArg_ParseTuple(args, "O!O!", &PyCObject_Type, &pytface, &PyCObject_Type, &pyrasty))
272         {
273                 MTFace *tface = (MTFace*) PyCObject_AsVoidPtr(pytface);
274                 RAS_IRasterizer *rasty = (RAS_IRasterizer*) PyCObject_AsVoidPtr(pyrasty);
275                 Image *ima = (Image*)tface->tpage;
276                 GPU_update_image_time(ima, rasty->GetTime());
277
278                 Py_RETURN_NONE;
279         }
280         
281         return NULL;
282 }
283
284 KX_PYMETHODDEF_DOC(KX_PolygonMaterial, setTexture, "setTexture(tface)")
285 {
286         PyObject *pytface;
287         if (PyArg_ParseTuple(args, "O!", &PyCObject_Type, &pytface))
288         {
289                 MTFace *tface = (MTFace*) PyCObject_AsVoidPtr(pytface);
290                 GPU_set_tpage(tface);
291                 Py_RETURN_NONE;
292         }
293         
294         return NULL;
295 }
296
297 KX_PYMETHODDEF_DOC(KX_PolygonMaterial, activate, "activate(rasty, cachingInfo)")
298 {
299         PyObject *pyrasty, *pyCachingInfo;
300         if (PyArg_ParseTuple(args, "O!O!", &PyCObject_Type, &pyrasty, &PyCObject_Type, &pyCachingInfo))
301         {
302                 RAS_IRasterizer *rasty = static_cast<RAS_IRasterizer*>(PyCObject_AsVoidPtr(pyrasty));
303                 TCachingInfo *cachingInfo = static_cast<TCachingInfo*>(PyCObject_AsVoidPtr(pyCachingInfo));
304                 if (rasty && cachingInfo)
305                 {
306                         DefaultActivate(rasty, *cachingInfo);
307                         Py_RETURN_NONE;
308                 }
309         }
310         
311         return NULL;
312 }
313
314 PyObject* KX_PolygonMaterial::pyattr_get_texture(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
315 {
316         KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v);
317         return PyString_FromString(self->m_texturename.ReadPtr());
318 }
319
320 PyObject* KX_PolygonMaterial::pyattr_get_material(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
321 {
322         KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v);
323         return PyString_FromString(self->m_materialname.ReadPtr());
324 }
325
326 /* this does not seem useful */
327 PyObject* KX_PolygonMaterial::pyattr_get_tface(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
328 {
329         KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v);
330         return PyCObject_FromVoidPtr(self->m_tface, NULL);
331 }
332
333 PyObject* KX_PolygonMaterial::pyattr_get_gl_texture(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
334 {
335         KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v);
336         Image *ima = self->m_tface->tpage;
337         return PyInt_FromLong(ima ? ima->bindcode:0);
338 }
339
340
341 PyObject* KX_PolygonMaterial::pyattr_get_diffuse(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
342 {
343         KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v);
344         return PyObjectFrom(self->m_diffuse);
345 }
346
347 int KX_PolygonMaterial::pyattr_set_diffuse(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
348 {
349         KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v);
350         MT_Vector3 vec;
351         
352         if (!PyVecTo(value, vec))
353                 return -1;
354         
355         self->m_diffuse= vec;
356         return 0;
357 }
358
359 PyObject* KX_PolygonMaterial::pyattr_get_specular(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
360 {
361         KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v);
362         return PyObjectFrom(self->m_specular);
363 }
364
365 int KX_PolygonMaterial::pyattr_set_specular(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
366 {
367         KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v);
368         MT_Vector3 vec;
369         
370         if (!PyVecTo(value, vec))
371                 return -1;
372         
373         self->m_specular= vec;
374         return 0;
375 }