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