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