f89b918f31bc9e2526ce7ded0ca7ad9be334daec
[blender.git] / source / gameengine / Ketsji / KX_PolygonMaterial.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file gameengine/Ketsji/KX_PolygonMaterial.cpp
29  *  \ingroup ketsji
30  */
31
32
33 #include <stddef.h>
34
35 #include "KX_PolygonMaterial.h"
36
37 #include "BKE_mesh.h"
38 #include "BKE_global.h"
39 #include "BKE_image.h"
40
41 #include "DNA_material_types.h"
42 #include "DNA_texture_types.h"
43 #include "DNA_image_types.h"
44 #include "DNA_meshdata_types.h"
45
46 #include "IMB_imbuf_types.h"
47
48 #include "GPU_draw.h"
49
50 #include "MEM_guardedalloc.h"
51
52 #include "RAS_LightObject.h"
53 #include "RAS_MaterialBucket.h"
54
55 #include "KX_PyMath.h"
56
57 #define KX_POLYGONMATERIAL_CAPSULE_ID "KX_POLYGONMATERIAL_PTR"
58
59 KX_PolygonMaterial::KX_PolygonMaterial()
60                 : PyObjectPlus(),
61                   RAS_IPolyMaterial(),
62
63         m_material(NULL),
64 #ifdef WITH_PYTHON
65         m_pymaterial(NULL),
66 #endif
67         m_pass(0)
68 {
69         memset(&m_tface, 0, sizeof(m_tface));
70         memset(&m_mcol, 0, sizeof(m_mcol));
71 }
72
73 void KX_PolygonMaterial::Initialize(
74                 const STR_String &texname,
75                 Material* ma,
76                 int materialindex,
77                 int tile,
78                 int tilexrep,
79                 int tileyrep,
80                 int alphablend,
81                 bool alpha,
82                 bool zsort,
83                 bool light,
84                 int lightlayer,
85                 struct MTFace* tface,
86                 unsigned int* mcol)
87 {
88         RAS_IPolyMaterial::Initialize(
89                                                         texname,
90                                                         ma?ma->id.name:"",
91                                                         materialindex,
92                                                         tile,
93                                                         tilexrep,
94                                                         tileyrep,
95                                                         alphablend,
96                                                         alpha,
97                                                         zsort,
98                                                         light,
99                                                         (texname && texname != ""?true:false), /* if we have a texture we have image */
100                                                         ma?&ma->game:NULL);
101
102         if (tface) {
103                 m_tface = *tface;
104         }
105         else {
106                 memset(&m_tface, 0, sizeof(m_tface));
107         }
108         if (mcol) {
109                 m_mcol = *mcol;
110         }
111         else {
112                 m_mcol = 0;
113         }
114
115         m_material = ma;
116 #ifdef WITH_PYTHON
117         m_pymaterial = 0;
118 #endif
119         m_pass = 0;
120 }
121
122 KX_PolygonMaterial::~KX_PolygonMaterial()
123 {
124 #ifdef WITH_PYTHON
125         if (m_pymaterial)
126         {
127                 Py_DECREF(m_pymaterial);
128         }
129 #endif // WITH_PYTHON
130 }
131
132 Image *KX_PolygonMaterial::GetBlenderImage() const
133 {
134         return m_tface.tpage;
135 }
136
137 bool KX_PolygonMaterial::Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const 
138 {
139         bool dopass = false;
140
141 #ifdef WITH_PYTHON
142         if (m_pymaterial)
143         {
144                 PyObject *pyRasty = PyCapsule_New((void*)rasty, KX_POLYGONMATERIAL_CAPSULE_ID, NULL);   /* new reference */
145                 PyObject *pyCachingInfo = PyCapsule_New((void*) &cachingInfo, KX_POLYGONMATERIAL_CAPSULE_ID, NULL); /* new reference */
146                 PyObject *ret = PyObject_CallMethod(m_pymaterial, (char *)"activate", (char *)"(NNO)", pyRasty, pyCachingInfo, (PyObject *) this->m_proxy);
147                 if (ret)
148                 {
149                         bool value = PyLong_AsSsize_t(ret);
150                         Py_DECREF(ret);
151                         dopass = value;
152                 }
153                 else
154                 {
155                         PyErr_Print();
156                         PyErr_Clear();
157                         PySys_SetObject( (char *)"last_traceback", NULL);
158                 }
159         }
160         else
161 #endif // WITH_PYTHON
162         {
163                 switch (m_pass++)
164                 {
165                         case 0:
166                                 DefaultActivate(rasty, cachingInfo);
167                                 dopass = true;
168                                 break;
169                         default:
170                                 m_pass = 0;
171                                 dopass = false;
172                                 break;
173                 }
174         }
175         
176         return dopass;
177 }
178
179 void KX_PolygonMaterial::DefaultActivate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const 
180 {
181         if (GetCachingInfo() != cachingInfo)
182         {
183                 if (!cachingInfo)
184                         GPU_set_tpage(NULL, 0, 0);
185
186                 cachingInfo = GetCachingInfo();
187
188                 if ((m_drawingmode & RAS_IRasterizer::KX_TEX)&& (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED))
189                 {
190                         Image *ima = m_tface.tpage;
191                         GPU_update_image_time(ima, rasty->GetTime());
192                         GPU_set_tpage(&m_tface, 1, m_alphablend);
193                 }
194                 else
195                         GPU_set_tpage(NULL, 0, 0);
196                 
197                 if (m_drawingmode & RAS_IRasterizer::KX_BACKCULL)
198                         rasty->SetCullFace(true);
199                 else
200                         rasty->SetCullFace(false);
201
202                 if ((m_drawingmode & RAS_IRasterizer::KX_LINES) ||
203                         (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME))
204                         rasty->SetLines(true);
205                 else
206                         rasty->SetLines(false);
207                 rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity);
208                 rasty->SetShinyness(m_shininess);
209                 rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0);
210                 if (m_material)
211                         rasty->SetPolygonOffset(-m_material->zoffs, 0.0);
212         }
213
214         //rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity);
215         //rasty->SetShinyness(m_shininess);
216         //rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0);
217         //if (m_material)
218         //      rasty->SetPolygonOffset(-m_material->zoffs, 0.0);
219 }
220
221 void KX_PolygonMaterial::GetMaterialRGBAColor(unsigned char *rgba) const
222 {
223         if (m_material) {
224                 *rgba++ = (unsigned char) (m_material->r*255.0);
225                 *rgba++ = (unsigned char) (m_material->g*255.0);
226                 *rgba++ = (unsigned char) (m_material->b*255.0);
227                 *rgba++ = (unsigned char) (m_material->alpha*255.0);
228         } else
229                 RAS_IPolyMaterial::GetMaterialRGBAColor(rgba);
230 }
231
232 #ifdef WITH_PYTHON
233
234 //----------------------------------------------------------------------------
235 //Python
236
237
238 PyMethodDef KX_PolygonMaterial::Methods[] = {
239         KX_PYMETHODTABLE(KX_PolygonMaterial, setCustomMaterial),
240         KX_PYMETHODTABLE(KX_PolygonMaterial, updateTexture),
241         KX_PYMETHODTABLE(KX_PolygonMaterial, setTexture),
242         KX_PYMETHODTABLE(KX_PolygonMaterial, activate),
243 //      KX_PYMETHODTABLE(KX_PolygonMaterial, setPerPixelLights),
244         
245         {NULL,NULL} //Sentinel
246 };
247
248 PyAttributeDef KX_PolygonMaterial::Attributes[] = {
249         KX_PYATTRIBUTE_RO_FUNCTION("texture",   KX_PolygonMaterial, pyattr_get_texture),
250         KX_PYATTRIBUTE_RO_FUNCTION("material",  KX_PolygonMaterial, pyattr_get_material), /* should probably be .name ? */
251         
252         KX_PYATTRIBUTE_INT_RW("tile", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_tile),
253         KX_PYATTRIBUTE_INT_RW("tilexrep", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_tilexrep),
254         KX_PYATTRIBUTE_INT_RW("tileyrep", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_tileyrep),
255         KX_PYATTRIBUTE_INT_RW("drawingmode", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_drawingmode),
256         //KX_PYATTRIBUTE_INT_RW("lightlayer", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_lightlayer),
257
258         KX_PYATTRIBUTE_BOOL_RW("transparent", KX_PolygonMaterial, m_alpha),
259         KX_PYATTRIBUTE_BOOL_RW("zsort", KX_PolygonMaterial, m_zsort),
260         
261         KX_PYATTRIBUTE_FLOAT_RW("shininess", 0.0f, 1000.0f, KX_PolygonMaterial, m_shininess),
262         KX_PYATTRIBUTE_FLOAT_RW("specularity", 0.0f, 1000.0f, KX_PolygonMaterial, m_specularity),
263         
264         KX_PYATTRIBUTE_RW_FUNCTION("diffuse", KX_PolygonMaterial, pyattr_get_diffuse, pyattr_set_diffuse),
265         KX_PYATTRIBUTE_RW_FUNCTION("specular",KX_PolygonMaterial, pyattr_get_specular, pyattr_set_specular),
266         
267         KX_PYATTRIBUTE_RO_FUNCTION("tface",     KX_PolygonMaterial, pyattr_get_tface), /* How the heck is this even useful??? - Campbell */
268         KX_PYATTRIBUTE_RO_FUNCTION("gl_texture", KX_PolygonMaterial, pyattr_get_gl_texture), /* could be called 'bindcode' */
269         
270         /* triangle used to be an attribute, removed for 2.49, nobody should be using it */
271         { NULL }        //Sentinel
272 };
273
274 PyTypeObject KX_PolygonMaterial::Type = {
275         PyVarObject_HEAD_INIT(NULL, 0)
276         "KX_PolygonMaterial",
277         sizeof(PyObjectPlus_Proxy),
278         0,
279         py_base_dealloc,
280         0,
281         0,
282         0,
283         0,
284         py_base_repr,
285         0,0,0,0,0,0,0,0,0,
286         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
287         0,0,0,0,0,0,0,
288         Methods,
289         0,
290         0,
291         &PyObjectPlus::Type,
292         0,0,0,0,0,0,
293         py_base_new
294 };
295
296 KX_PYMETHODDEF_DOC(KX_PolygonMaterial, setCustomMaterial, "setCustomMaterial(material)")
297 {
298         PyObject *material;
299         if (PyArg_ParseTuple(args, "O:setCustomMaterial", &material))
300         {
301                 if (m_pymaterial) {
302                         Py_DECREF(m_pymaterial);
303                 }
304                 m_pymaterial = material;
305                 Py_INCREF(m_pymaterial);
306                 Py_RETURN_NONE;
307         }
308         
309         return NULL;
310 }
311
312 KX_PYMETHODDEF_DOC(KX_PolygonMaterial, updateTexture, "updateTexture(tface, rasty)")
313 {
314         PyObject *pyrasty, *pytface;
315         if (PyArg_ParseTuple(args, "O!O!:updateTexture", &PyCapsule_Type, &pytface, &PyCapsule_Type, &pyrasty))
316         {
317                 MTFace *tface = (MTFace*) PyCapsule_GetPointer(pytface, KX_POLYGONMATERIAL_CAPSULE_ID);
318                 RAS_IRasterizer *rasty = (RAS_IRasterizer*) PyCapsule_GetPointer(pyrasty, KX_POLYGONMATERIAL_CAPSULE_ID);
319                 Image *ima = (Image*)tface->tpage;
320                 GPU_update_image_time(ima, rasty->GetTime());
321
322                 Py_RETURN_NONE;
323         }
324         
325         return NULL;
326 }
327
328 KX_PYMETHODDEF_DOC(KX_PolygonMaterial, setTexture, "setTexture(tface)")
329 {
330         PyObject *pytface;
331         if (PyArg_ParseTuple(args, "O!:setTexture", &PyCapsule_Type, &pytface))
332         {
333                 MTFace *tface = (MTFace*) PyCapsule_GetPointer(pytface, KX_POLYGONMATERIAL_CAPSULE_ID);
334                 GPU_set_tpage(tface, 1, m_alphablend);
335                 Py_RETURN_NONE;
336         }
337         
338         return NULL;
339 }
340
341 KX_PYMETHODDEF_DOC(KX_PolygonMaterial, activate, "activate(rasty, cachingInfo)")
342 {
343         PyObject *pyrasty, *pyCachingInfo;
344         if (PyArg_ParseTuple(args, "O!O!:activate", &PyCapsule_Type, &pyrasty, &PyCapsule_Type, &pyCachingInfo))
345         {
346                 RAS_IRasterizer *rasty = static_cast<RAS_IRasterizer*>(PyCapsule_GetPointer(pyrasty, KX_POLYGONMATERIAL_CAPSULE_ID));
347                 TCachingInfo *cachingInfo = static_cast<TCachingInfo*>(PyCapsule_GetPointer(pyCachingInfo, KX_POLYGONMATERIAL_CAPSULE_ID));
348                 if (rasty && cachingInfo)
349                 {
350                         DefaultActivate(rasty, *cachingInfo);
351                         Py_RETURN_NONE;
352                 }
353         }
354         
355         return NULL;
356 }
357
358 PyObject *KX_PolygonMaterial::pyattr_get_texture(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
359 {
360         KX_PolygonMaterial* self = static_cast<KX_PolygonMaterial*>(self_v);
361         return PyUnicode_From_STR_String(self->m_texturename);
362 }
363
364 PyObject *KX_PolygonMaterial::pyattr_get_material(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
365 {
366         KX_PolygonMaterial* self = static_cast<KX_PolygonMaterial*>(self_v);
367         return PyUnicode_From_STR_String(self->m_materialname);
368 }
369
370 /* this does not seem useful */
371 PyObject *KX_PolygonMaterial::pyattr_get_tface(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
372 {
373         KX_PolygonMaterial* self = static_cast<KX_PolygonMaterial*>(self_v);
374         return PyCapsule_New(&self->m_tface, KX_POLYGONMATERIAL_CAPSULE_ID, NULL);
375 }
376
377 PyObject *KX_PolygonMaterial::pyattr_get_gl_texture(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
378 {
379         KX_PolygonMaterial* self = static_cast<KX_PolygonMaterial*>(self_v);
380         int bindcode= 0;
381         if (self->m_tface.tpage)
382                 bindcode= self->m_tface.tpage->bindcode;
383         
384         return PyLong_FromSsize_t(bindcode);
385 }
386
387
388 PyObject *KX_PolygonMaterial::pyattr_get_diffuse(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
389 {
390         KX_PolygonMaterial* self = static_cast<KX_PolygonMaterial*>(self_v);
391         return PyObjectFrom(self->m_diffuse);
392 }
393
394 int KX_PolygonMaterial::pyattr_set_diffuse(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
395 {
396         KX_PolygonMaterial* self = static_cast<KX_PolygonMaterial*>(self_v);
397         MT_Vector3 vec;
398         
399         if (!PyVecTo(value, vec))
400                 return PY_SET_ATTR_FAIL;
401         
402         self->m_diffuse= vec;
403         return PY_SET_ATTR_SUCCESS;
404 }
405
406 PyObject *KX_PolygonMaterial::pyattr_get_specular(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
407 {
408         KX_PolygonMaterial* self = static_cast<KX_PolygonMaterial*>(self_v);
409         return PyObjectFrom(self->m_specular);
410 }
411
412 int KX_PolygonMaterial::pyattr_set_specular(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
413 {
414         KX_PolygonMaterial* self = static_cast<KX_PolygonMaterial*>(self_v);
415         MT_Vector3 vec;
416         
417         if (!PyVecTo(value, vec))
418                 return PY_SET_ATTR_FAIL;
419         
420         self->m_specular= vec;
421         return PY_SET_ATTR_SUCCESS;
422 }
423
424 #endif // WITH_PYTHON