|
Blender
V2.59
|
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", ¶m, &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 };