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