Blender  V2.59
Texture.cpp
Go to the documentation of this file.
00001 
00004 /* $Id: Texture.cpp 35176 2011-02-25 13:39:34Z jesterking $
00005 -----------------------------------------------------------------------------
00006 This source file is part of VideoTexture library
00007 
00008 Copyright (c) 2007 The Zdeno Ash Miklas
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 
00026 // implementation
00027 
00028 #include <PyObjectPlus.h>
00029 #include <structmember.h>
00030 
00031 #include <KX_GameObject.h>
00032 #include <RAS_MeshObject.h>
00033 #include <DNA_mesh_types.h>
00034 #include <DNA_meshdata_types.h>
00035 #include <DNA_image_types.h>
00036 #include <IMB_imbuf_types.h>
00037 #include <KX_PolygonMaterial.h>
00038 
00039 #include <MEM_guardedalloc.h>
00040 
00041 #include <KX_BlenderMaterial.h>
00042 #include <BL_Texture.h>
00043 
00044 #include "KX_KetsjiEngine.h"
00045 #include "KX_PythonInit.h"
00046 #include "Texture.h"
00047 #include "ImageBase.h"
00048 #include "Exception.h"
00049 
00050 #include <memory.h>
00051 #include "GL/glew.h"
00052 
00053 
00054 // macro for exception handling and logging
00055 #define CATCH_EXCP catch (Exception & exp) \
00056 { exp.report(); return NULL; }
00057 
00058 
00059 // Blender GameObject type
00060 BlendType<KX_GameObject> gameObjectType ("KX_GameObject");
00061 
00062 
00063 // load texture
00064 void loadTexture (unsigned int texId, unsigned int * texture, short * size,
00065                                   bool mipmap)
00066 {
00067         // load texture for rendering
00068         glBindTexture(GL_TEXTURE_2D, texId);
00069         if (mipmap)
00070         {
00071                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
00072                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00073                 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE, texture);
00074         } 
00075         else
00076         {
00077                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00078                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00079                 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, size[0], size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
00080         }
00081         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00082 }
00083 
00084 
00085 // get pointer to material
00086 RAS_IPolyMaterial * getMaterial (PyObject *obj, short matID)
00087 {
00088         // if object is available
00089         if (obj != NULL)
00090         {
00091                 // get pointer to texture image
00092                 KX_GameObject * gameObj = gameObjectType.checkType(obj);
00093                 if (gameObj != NULL && gameObj->GetMeshCount() > 0)
00094                 {
00095                         // get material from mesh
00096                         RAS_MeshObject * mesh = gameObj->GetMesh(0);
00097                         RAS_MeshMaterial *meshMat = mesh->GetMeshMaterial(matID);
00098                         if (meshMat != NULL && meshMat->m_bucket != NULL)
00099                                 // return pointer to polygon or blender material
00100                                 return meshMat->m_bucket->GetPolyMaterial();
00101                 }
00102         }
00103         // otherwise material was not found
00104         return NULL;
00105 }
00106 
00107 
00108 // get material ID
00109 short getMaterialID (PyObject * obj, char * name)
00110 {
00111         // search for material
00112         for (short matID = 0;; ++matID)
00113         {
00114                 // get material
00115                 RAS_IPolyMaterial * mat = getMaterial(obj, matID);
00116                 // if material is not available, report that no material was found
00117                 if (mat == NULL) 
00118                         break;
00119                 // name is a material name if it starts with MA and a UV texture name if it starts with IM
00120                 if (name[0] == 'I' && name[1] == 'M')
00121                 {
00122                         // if texture name matches
00123                         if (strcmp(mat->GetTextureName().ReadPtr(), name) == 0)
00124                                 return matID;
00125                 } else 
00126                 {
00127                         // if material name matches
00128                         if (strcmp(mat->GetMaterialName().ReadPtr(), name) == 0)
00129                                 return matID;
00130                 }
00131         }
00132         // material was not found
00133         return -1;
00134 }
00135 
00136 
00137 // Texture object allocation
00138 PyObject * Texture_new (PyTypeObject *type, PyObject *args, PyObject *kwds)
00139 {
00140         // allocate object
00141         Texture * self = reinterpret_cast<Texture*>(type->tp_alloc(type, 0));
00142         // initialize object structure
00143         self->m_actTex = 0;
00144         self->m_orgSaved = false;
00145         self->m_imgTexture = NULL;
00146         self->m_matTexture = NULL;
00147         self->m_mipmap = false;
00148         self->m_scaledImg = NULL;
00149         self->m_scaledImgSize = 0;
00150         self->m_source = NULL;
00151         self->m_lastClock = 0.0;
00152         // return allocated object
00153         return reinterpret_cast<PyObject*>(self);
00154 }
00155 
00156 
00157 // forward declaration
00158 PyObject * Texture_close(Texture * self);
00159 int Texture_setSource (Texture * self, PyObject * value, void * closure);
00160 
00161 
00162 // Texture object deallocation
00163 void Texture_dealloc (Texture * self)
00164 {
00165         // release renderer
00166         Py_XDECREF(self->m_source);
00167         // close texture
00168         PyObject* ret = Texture_close(self);
00169         Py_DECREF(ret);
00170         // release scaled image buffer
00171         delete [] self->m_scaledImg;
00172         // release object
00173         ((PyObject *)self)->ob_type->tp_free((PyObject*)self);
00174 }
00175 
00176 
00177 ExceptionID MaterialNotAvail;
00178 ExpDesc MaterialNotAvailDesc (MaterialNotAvail, "Texture material is not available");
00179 
00180 // Texture object initialization
00181 int Texture_init (Texture *self, PyObject *args, PyObject *kwds)
00182 {
00183         // parameters - game object with video texture
00184         PyObject * obj = NULL;
00185         // material ID
00186         short matID = 0;
00187         // texture ID
00188         short texID = 0;
00189         // texture object with shared texture ID
00190         Texture * texObj = NULL;
00191 
00192         static const char *kwlist[] = {"gameObj", "materialID", "textureID", "textureObj", NULL};
00193 
00194         // get parameters
00195         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|hhO!",
00196                 const_cast<char**>(kwlist), &obj, &matID, &texID, &TextureType,
00197                 &texObj))
00198                 return -1; 
00199 
00200         // if parameters are available
00201         if (obj != NULL)
00202         {
00203                 // process polygon material or blender material
00204                 try
00205                 {
00206                         // get pointer to texture image
00207                         RAS_IPolyMaterial * mat = getMaterial(obj, matID);
00208                         if (mat != NULL)
00209                         {
00210                                 // is it blender material or polygon material
00211                                 if (mat->GetFlag() & RAS_BLENDERGLSL) 
00212                                 {
00213                                         self->m_imgTexture = static_cast<KX_BlenderMaterial*>(mat)->getImage(texID);
00214                                         self->m_useMatTexture = false;
00215                                 } else if (mat->GetFlag() & RAS_BLENDERMAT)
00216                                 {
00217                                         // get blender material texture
00218                                         self->m_matTexture = static_cast<KX_BlenderMaterial*>(mat)->getTex(texID);
00219                                         self->m_useMatTexture = true;
00220                                 }
00221                                 else
00222                                 {
00223                                         // get texture pointer from polygon material
00224                                         MTFace * tface = static_cast<KX_PolygonMaterial*>(mat)->GetMTFace();
00225                                         self->m_imgTexture = (Image*)tface->tpage;
00226                                         self->m_useMatTexture = false;
00227                                 }
00228                         }
00229                         // check if texture is available, if not, initialization failed
00230                         if (self->m_imgTexture == NULL && self->m_matTexture == NULL)
00231                                 // throw exception if initialization failed
00232                                 THRWEXCP(MaterialNotAvail, S_OK);
00233 
00234                         // if texture object is provided
00235                         if (texObj != NULL)
00236                         {
00237                                 // copy texture code
00238                                 self->m_actTex = texObj->m_actTex;
00239                                 self->m_mipmap = texObj->m_mipmap;
00240                                 if (texObj->m_source != NULL)
00241                                         Texture_setSource(self, reinterpret_cast<PyObject*>(texObj->m_source), NULL);
00242                         }
00243                         else
00244                                 // otherwise generate texture code
00245                                 glGenTextures(1, (GLuint*)&self->m_actTex);
00246                 }
00247                 catch (Exception & exp)
00248                 {
00249                         exp.report();
00250                         return -1;
00251                 }
00252         }
00253         // initialization succeded
00254         return 0;
00255 }
00256 
00257 
00258 // close added texture
00259 PyObject * Texture_close(Texture * self)
00260 {
00261         // restore texture
00262         if (self->m_orgSaved)
00263         {
00264                 self->m_orgSaved = false;
00265                 // restore original texture code
00266                 if (self->m_useMatTexture)
00267                         self->m_matTexture->swapTexture(self->m_orgTex);
00268                 else
00269                         self->m_imgTexture->bindcode = self->m_orgTex;
00270                 // drop actual texture
00271                 if (self->m_actTex != 0)
00272                 {
00273                         glDeleteTextures(1, (GLuint *)&self->m_actTex);
00274                         self->m_actTex = 0;
00275                 }
00276         }
00277         Py_RETURN_NONE;
00278 }
00279 
00280 
00281 // refresh texture
00282 PyObject * Texture_refresh (Texture * self, PyObject * args)
00283 {
00284         // get parameter - refresh source
00285         PyObject * param;
00286         double ts = -1.0;
00287 
00288         if (!PyArg_ParseTuple(args, "O|d:refresh", &param, &ts) || !PyBool_Check(param))
00289         {
00290                 // report error
00291                 PyErr_SetString(PyExc_TypeError, "The value must be a bool");
00292                 return NULL;
00293         }
00294         // some trick here: we are in the business of loading a texture,
00295         // no use to do it if we are still in the same rendering frame.
00296         // We find this out by looking at the engine current clock time
00297         KX_KetsjiEngine* engine = KX_GetActiveEngine();
00298         if (engine->GetClockTime() != self->m_lastClock) 
00299         {
00300                 self->m_lastClock = engine->GetClockTime();
00301                 // set source refresh
00302                 bool refreshSource = (param == Py_True);
00303                 // try to proces texture from source
00304                 try
00305                 {
00306                         // if source is available
00307                         if (self->m_source != NULL)
00308                         {
00309                                 // check texture code
00310                                 if (!self->m_orgSaved)
00311                                 {
00312                                         self->m_orgSaved = true;
00313                                         // save original image code
00314                                         if (self->m_useMatTexture)
00315                                                 self->m_orgTex = self->m_matTexture->swapTexture(self->m_actTex);
00316                                         else
00317                                         {
00318                                                 self->m_orgTex = self->m_imgTexture->bindcode;
00319                                                 self->m_imgTexture->bindcode = self->m_actTex;
00320                                         }
00321                                 }
00322 
00323                                 // get texture
00324                                 unsigned int * texture = self->m_source->m_image->getImage(self->m_actTex, ts);
00325                                 // if texture is available
00326                                 if (texture != NULL)
00327                                 {
00328                                         // get texture size
00329                                         short * orgSize = self->m_source->m_image->getSize();
00330                                         // calc scaled sizes
00331                                         short size[] = {ImageBase::calcSize(orgSize[0]), ImageBase::calcSize(orgSize[1])};
00332                                         // scale texture if needed
00333                                         if (size[0] != orgSize[0] || size[1] != orgSize[1])
00334                                         {
00335                                                 // if scaled image buffer is smaller than needed
00336                                                 if (self->m_scaledImgSize < (unsigned int)(size[0] * size[1]))
00337                                                 {
00338                                                         // new size
00339                                                         self->m_scaledImgSize = size[0] * size[1];
00340                                                         // allocate scaling image
00341                                                         delete [] self->m_scaledImg;
00342                                                         self->m_scaledImg = new unsigned int[self->m_scaledImgSize];
00343                                                 }
00344                                                 // scale texture
00345                                                 gluScaleImage(GL_RGBA, orgSize[0], orgSize[1], GL_UNSIGNED_BYTE, texture,
00346                                                         size[0], size[1], GL_UNSIGNED_BYTE, self->m_scaledImg);
00347                                                 // use scaled image instead original
00348                                                 texture = self->m_scaledImg;
00349                                         }
00350                                         // load texture for rendering
00351                                         loadTexture (self->m_actTex, texture, size, self->m_mipmap);
00352 
00353                                         // refresh texture source, if required
00354                                         if (refreshSource) self->m_source->m_image->refresh();
00355                                 }
00356                         }
00357                 }
00358                 CATCH_EXCP;
00359         }
00360         Py_RETURN_NONE;
00361 }
00362 
00363 // get OpenGL Bind Id
00364 PyObject * Texture_getBindId (Texture * self, void * closure)
00365 {
00366         unsigned int id = self->m_actTex;
00367         return Py_BuildValue("h", id);
00368 }
00369 
00370 // get mipmap value
00371 PyObject * Texture_getMipmap (Texture * self, void * closure)
00372 {
00373         // return true if flag is set, otherwise false
00374         if (self->m_mipmap) Py_RETURN_TRUE;
00375         else Py_RETURN_FALSE;
00376 }
00377 
00378 // set mipmap value
00379 int Texture_setMipmap (Texture * self, PyObject * value, void * closure)
00380 {
00381         // check parameter, report failure
00382         if (value == NULL || !PyBool_Check(value))
00383         {
00384                 PyErr_SetString(PyExc_TypeError, "The value must be a bool");
00385                 return -1;
00386         }
00387         // set mipmap
00388         self->m_mipmap = value == Py_True;
00389         // success
00390         return 0;
00391 }
00392 
00393 
00394 // get source object
00395 PyObject * Texture_getSource (Texture * self, PyObject * value, void * closure)
00396 {
00397         // if source exists
00398         if (self->m_source != NULL)
00399         {
00400                 Py_INCREF(self->m_source);
00401                 return reinterpret_cast<PyObject*>(self->m_source);
00402         }
00403         // otherwise return None
00404         Py_RETURN_NONE;
00405 }
00406 
00407 
00408 // set source object
00409 int Texture_setSource (Texture * self, PyObject * value, void * closure)
00410 {
00411         // check new value
00412         if (value == NULL || !pyImageTypes.in(value->ob_type))
00413         {
00414                 // report value error
00415                 PyErr_SetString(PyExc_TypeError, "Invalid type of value");
00416                 return -1;
00417         }
00418         // increase ref count for new value
00419         Py_INCREF(value);
00420         // release previous
00421         Py_XDECREF(self->m_source);
00422         // set new value
00423         self->m_source = reinterpret_cast<PyImage*>(value);
00424         // return success
00425         return 0;
00426 }
00427 
00428 
00429 // class Texture methods
00430 static PyMethodDef textureMethods[] =
00431 {
00432         { "close", (PyCFunction)Texture_close, METH_NOARGS, "Close dynamic texture and restore original"},
00433         { "refresh", (PyCFunction)Texture_refresh, METH_VARARGS, "Refresh texture from source"},
00434         {NULL}  /* Sentinel */
00435 };
00436 
00437 // class Texture attributes
00438 static PyGetSetDef textureGetSets[] =
00439 { 
00440         {(char*)"source", (getter)Texture_getSource, (setter)Texture_setSource, (char*)"source of texture", NULL},
00441         {(char*)"mipmap", (getter)Texture_getMipmap, (setter)Texture_setMipmap, (char*)"mipmap texture", NULL},
00442         {(char*)"bindId", (getter)Texture_getBindId, NULL, (char*)"OpenGL Bind Name", NULL},
00443         {NULL}
00444 };
00445 
00446 
00447 // class Texture declaration
00448 PyTypeObject TextureType =
00449 {
00450         PyVarObject_HEAD_INIT(NULL, 0)
00451         "VideoTexture.Texture",   /*tp_name*/
00452         sizeof(Texture),           /*tp_basicsize*/
00453         0,                         /*tp_itemsize*/
00454         (destructor)Texture_dealloc,/*tp_dealloc*/
00455         0,                         /*tp_print*/
00456         0,                         /*tp_getattr*/
00457         0,                         /*tp_setattr*/
00458         0,                         /*tp_compare*/
00459         0,                         /*tp_repr*/
00460         0,                         /*tp_as_number*/
00461         0,                         /*tp_as_sequence*/
00462         0,                         /*tp_as_mapping*/
00463         0,                         /*tp_hash */
00464         0,                         /*tp_call*/
00465         0,                         /*tp_str*/
00466         0,                         /*tp_getattro*/
00467         0,                         /*tp_setattro*/
00468         &imageBufferProcs,         /*tp_as_buffer*/
00469         Py_TPFLAGS_DEFAULT,        /*tp_flags*/
00470         "Texture objects",       /* tp_doc */
00471         0,                             /* tp_traverse */
00472         0,                             /* tp_clear */
00473         0,                             /* tp_richcompare */
00474         0,                             /* tp_weaklistoffset */
00475         0,                             /* tp_iter */
00476         0,                             /* tp_iternext */
00477         textureMethods,      /* tp_methods */
00478         0,                   /* tp_members */
00479         textureGetSets,            /* tp_getset */
00480         0,                         /* tp_base */
00481         0,                         /* tp_dict */
00482         0,                         /* tp_descr_get */
00483         0,                         /* tp_descr_set */
00484         0,                         /* tp_dictoffset */
00485         (initproc)Texture_init,    /* tp_init */
00486         0,                         /* tp_alloc */
00487         Texture_new,               /* tp_new */
00488 };