Blender V2.61 - r43446

Texture.cpp

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