Texture.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /*
  2. * ***** BEGIN GPL LICENSE BLOCK *****
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software Foundation,
  16. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. *
  18. * Copyright (c) 2007 The Zdeno Ash Miklas
  19. *
  20. * This source file is part of VideoTexture library
  21. *
  22. * Contributor(s):
  23. *
  24. * ***** END GPL LICENSE BLOCK *****
  25. */
  26. /** \file gameengine/VideoTexture/Texture.cpp
  27. * \ingroup bgevideotex
  28. */
  29. // implementation
  30. #include "EXP_PyObjectPlus.h"
  31. #include <structmember.h>
  32. #include "KX_GameObject.h"
  33. #include "KX_Light.h"
  34. #include "RAS_MeshObject.h"
  35. #include "RAS_ILightObject.h"
  36. #include "DNA_mesh_types.h"
  37. #include "DNA_meshdata_types.h"
  38. #include "DNA_image_types.h"
  39. #include "IMB_imbuf_types.h"
  40. #include "BKE_image.h"
  41. #include "MEM_guardedalloc.h"
  42. #include "KX_BlenderMaterial.h"
  43. #include "BL_Texture.h"
  44. #include "KX_KetsjiEngine.h"
  45. #include "KX_PythonInit.h"
  46. #include "Texture.h"
  47. #include "ImageBase.h"
  48. #include "Exception.h"
  49. #include <memory.h>
  50. #include "GPU_glew.h"
  51. extern "C" {
  52. #include "IMB_imbuf.h"
  53. }
  54. // macro for exception handling and logging
  55. #define CATCH_EXCP catch (Exception & exp) \
  56. { exp.report(); return NULL; }
  57. // Blender GameObject type
  58. static BlendType<KX_GameObject> gameObjectType ("KX_GameObject");
  59. static BlendType<KX_LightObject> lightObjectType ("KX_LightObject");
  60. // load texture
  61. void loadTexture(unsigned int texId, unsigned int *texture, short *size,
  62. bool mipmap)
  63. {
  64. // load texture for rendering
  65. glBindTexture(GL_TEXTURE_2D, texId);
  66. if (mipmap)
  67. {
  68. int i;
  69. ImBuf *ibuf;
  70. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  71. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  72. ibuf = IMB_allocFromBuffer(texture, NULL, size[0], size[1]);
  73. IMB_makemipmap(ibuf, true);
  74. for (i = 0; i < ibuf->miptot; i++) {
  75. ImBuf *mip = IMB_getmipmap(ibuf, i);
  76. glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect);
  77. }
  78. IMB_freeImBuf(ibuf);
  79. }
  80. else
  81. {
  82. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  83. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  84. glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, size[0], size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
  85. }
  86. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  87. }
  88. // get pointer to material
  89. RAS_IPolyMaterial * getMaterial (PyObject *obj, short matID)
  90. {
  91. // if object is available
  92. if (obj != NULL)
  93. {
  94. // get pointer to texture image
  95. KX_GameObject * gameObj = gameObjectType.checkType(obj);
  96. if (gameObj != NULL && gameObj->GetMeshCount() > 0)
  97. {
  98. // get material from mesh
  99. RAS_MeshObject * mesh = gameObj->GetMesh(0);
  100. RAS_MeshMaterial *meshMat = mesh->GetMeshMaterial(matID);
  101. if (meshMat != NULL && meshMat->m_bucket != NULL)
  102. // return pointer to polygon or blender material
  103. return meshMat->m_bucket->GetPolyMaterial();
  104. }
  105. }
  106. // otherwise material was not found
  107. return NULL;
  108. }
  109. // get pointer to a lamp
  110. static KX_LightObject *getLamp(PyObject *obj)
  111. {
  112. // if object is available
  113. if (obj == NULL) return NULL;
  114. // returns NULL if obj is not a KX_LightObject
  115. return lightObjectType.checkType(obj);
  116. }
  117. // get material ID
  118. short getMaterialID(PyObject *obj, const char *name)
  119. {
  120. // search for material
  121. for (short matID = 0;; ++matID)
  122. {
  123. // get material
  124. RAS_IPolyMaterial * mat = getMaterial(obj, matID);
  125. // if material is not available, report that no material was found
  126. if (mat == NULL)
  127. break;
  128. // name is a material name if it starts with MA and a UV texture name if it starts with IM
  129. if (name[0] == 'I' && name[1] == 'M') {
  130. // if texture name matches
  131. if (strcmp(mat->GetTextureName().ReadPtr(), name) == 0)
  132. return matID;
  133. }
  134. else {
  135. // if material name matches
  136. if (strcmp(mat->GetMaterialName().ReadPtr(), name) == 0)
  137. return matID;
  138. }
  139. }
  140. // material was not found
  141. return -1;
  142. }
  143. // Texture object allocation
  144. static PyObject *Texture_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
  145. {
  146. // allocate object
  147. Texture * self = reinterpret_cast<Texture*>(type->tp_alloc(type, 0));
  148. // initialize object structure
  149. self->m_actTex = 0;
  150. self->m_orgSaved = false;
  151. self->m_imgBuf = NULL;
  152. self->m_imgTexture = NULL;
  153. self->m_matTexture = NULL;
  154. self->m_mipmap = false;
  155. self->m_scaledImBuf = NULL;
  156. self->m_source = NULL;
  157. self->m_lastClock = 0.0;
  158. // return allocated object
  159. return reinterpret_cast<PyObject*>(self);
  160. }
  161. // forward declaration
  162. PyObject *Texture_close(Texture *self);
  163. int Texture_setSource(Texture *self, PyObject *value, void *closure);
  164. // Texture object deallocation
  165. static void Texture_dealloc(Texture *self)
  166. {
  167. // release renderer
  168. Py_XDECREF(self->m_source);
  169. // close texture
  170. PyObject *ret = Texture_close(self);
  171. Py_DECREF(ret);
  172. // release scaled image buffer
  173. IMB_freeImBuf(self->m_scaledImBuf);
  174. // release object
  175. Py_TYPE((PyObject *)self)->tp_free((PyObject *)self);
  176. }
  177. ExceptionID MaterialNotAvail;
  178. ExpDesc MaterialNotAvailDesc(MaterialNotAvail, "Texture material is not available");
  179. // Texture object initialization
  180. static int Texture_init(Texture *self, PyObject *args, PyObject *kwds)
  181. {
  182. // parameters - game object with video texture
  183. PyObject *obj = NULL;
  184. // material ID
  185. short matID = 0;
  186. // texture ID
  187. short texID = 0;
  188. // texture object with shared texture ID
  189. Texture * texObj = NULL;
  190. static const char *kwlist[] = {"gameObj", "materialID", "textureID", "textureObj", NULL};
  191. // get parameters
  192. if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|hhO!",
  193. const_cast<char**>(kwlist), &obj, &matID, &texID, &TextureType,
  194. &texObj))
  195. return -1;
  196. // if parameters are available
  197. if (obj != NULL)
  198. {
  199. // process polygon material or blender material
  200. try
  201. {
  202. // get pointer to texture image
  203. RAS_IPolyMaterial * mat = getMaterial(obj, matID);
  204. KX_LightObject * lamp = getLamp(obj);
  205. if (mat != NULL)
  206. {
  207. // is it blender material or polygon material
  208. if (mat->GetFlag() & RAS_BLENDERGLSL)
  209. {
  210. self->m_imgTexture = static_cast<KX_BlenderMaterial*>(mat)->getImage(texID);
  211. self->m_useMatTexture = false;
  212. } else
  213. {
  214. // get blender material texture
  215. self->m_matTexture = static_cast<KX_BlenderMaterial*>(mat)->getTex(texID);
  216. self->m_useMatTexture = true;
  217. }
  218. }
  219. else if (lamp != NULL)
  220. {
  221. self->m_imgTexture = lamp->GetLightData()->GetTextureImage(texID);
  222. self->m_useMatTexture = false;
  223. }
  224. // check if texture is available, if not, initialization failed
  225. if (self->m_imgTexture == NULL && self->m_matTexture == NULL)
  226. // throw exception if initialization failed
  227. THRWEXCP(MaterialNotAvail, S_OK);
  228. // if texture object is provided
  229. if (texObj != NULL)
  230. {
  231. // copy texture code
  232. self->m_actTex = texObj->m_actTex;
  233. self->m_mipmap = texObj->m_mipmap;
  234. if (texObj->m_source != NULL)
  235. Texture_setSource(self, reinterpret_cast<PyObject*>(texObj->m_source), NULL);
  236. }
  237. else
  238. // otherwise generate texture code
  239. glGenTextures(1, (GLuint*)&self->m_actTex);
  240. }
  241. catch (Exception & exp)
  242. {
  243. exp.report();
  244. return -1;
  245. }
  246. }
  247. // initialization succeded
  248. return 0;
  249. }
  250. // close added texture
  251. PyObject *Texture_close(Texture * self)
  252. {
  253. // restore texture
  254. if (self->m_orgSaved)
  255. {
  256. self->m_orgSaved = false;
  257. // restore original texture code
  258. if (self->m_useMatTexture)
  259. self->m_matTexture->swapTexture(self->m_orgTex);
  260. else
  261. {
  262. self->m_imgTexture->bindcode[TEXTARGET_TEXTURE_2D] = self->m_orgTex;
  263. BKE_image_release_ibuf(self->m_imgTexture, self->m_imgBuf, NULL);
  264. self->m_imgBuf = NULL;
  265. }
  266. // drop actual texture
  267. if (self->m_actTex != 0)
  268. {
  269. glDeleteTextures(1, (GLuint *)&self->m_actTex);
  270. self->m_actTex = 0;
  271. }
  272. }
  273. Py_RETURN_NONE;
  274. }
  275. // refresh texture
  276. static PyObject *Texture_refresh(Texture *self, PyObject *args)
  277. {
  278. // get parameter - refresh source
  279. PyObject *param;
  280. double ts = -1.0;
  281. if (!PyArg_ParseTuple(args, "O|d:refresh", &param, &ts) || !PyBool_Check(param))
  282. {
  283. // report error
  284. PyErr_SetString(PyExc_TypeError, "The value must be a bool");
  285. return NULL;
  286. }
  287. // some trick here: we are in the business of loading a texture,
  288. // no use to do it if we are still in the same rendering frame.
  289. // We find this out by looking at the engine current clock time
  290. KX_KetsjiEngine* engine = KX_GetActiveEngine();
  291. if (engine->GetClockTime() != self->m_lastClock)
  292. {
  293. self->m_lastClock = engine->GetClockTime();
  294. // set source refresh
  295. bool refreshSource = (param == Py_True);
  296. // try to proces texture from source
  297. try
  298. {
  299. // if source is available
  300. if (self->m_source != NULL)
  301. {
  302. // check texture code
  303. if (!self->m_orgSaved)
  304. {
  305. self->m_orgSaved = true;
  306. // save original image code
  307. if (self->m_useMatTexture)
  308. self->m_orgTex = self->m_matTexture->swapTexture(self->m_actTex);
  309. else
  310. {
  311. // Swapping will work only if the GPU has already loaded the image.
  312. // If not, it will delete and overwrite our texture on next render.
  313. // To avoid that, we acquire the image buffer now.
  314. // WARNING: GPU has a ImageUser to pass, we don't. Using NULL
  315. // works on image file, not necessarily on other type of image.
  316. self->m_imgBuf = BKE_image_acquire_ibuf(self->m_imgTexture, NULL, NULL);
  317. self->m_orgTex = self->m_imgTexture->bindcode[TEXTARGET_TEXTURE_2D];
  318. self->m_imgTexture->bindcode[TEXTARGET_TEXTURE_2D] = self->m_actTex;
  319. }
  320. }
  321. // get texture
  322. unsigned int * texture = self->m_source->m_image->getImage(self->m_actTex, ts);
  323. // if texture is available
  324. if (texture != NULL)
  325. {
  326. // get texture size
  327. short * orgSize = self->m_source->m_image->getSize();
  328. // calc scaled sizes
  329. short size[2];
  330. if (GLEW_ARB_texture_non_power_of_two)
  331. {
  332. size[0] = orgSize[0];
  333. size[1] = orgSize[1];
  334. }
  335. else
  336. {
  337. size[0] = ImageBase::calcSize(orgSize[0]);
  338. size[1] = ImageBase::calcSize(orgSize[1]);
  339. }
  340. // scale texture if needed
  341. if (size[0] != orgSize[0] || size[1] != orgSize[1])
  342. {
  343. IMB_freeImBuf(self->m_scaledImBuf);
  344. self->m_scaledImBuf = IMB_allocFromBuffer(texture, NULL, orgSize[0], orgSize[1]);
  345. IMB_scaleImBuf(self->m_scaledImBuf, size[0], size[1]);
  346. // use scaled image instead original
  347. texture = self->m_scaledImBuf->rect;
  348. }
  349. // load texture for rendering
  350. loadTexture(self->m_actTex, texture, size, self->m_mipmap);
  351. }
  352. // refresh texture source, if required
  353. if (refreshSource) {
  354. self->m_source->m_image->refresh();
  355. }
  356. }
  357. }
  358. CATCH_EXCP;
  359. }
  360. Py_RETURN_NONE;
  361. }
  362. // get OpenGL Bind Id
  363. static PyObject *Texture_getBindId(Texture *self, void *closure)
  364. {
  365. unsigned int id = self->m_actTex;
  366. return Py_BuildValue("h", id);
  367. }
  368. // get mipmap value
  369. static PyObject *Texture_getMipmap(Texture *self, void *closure)
  370. {
  371. // return true if flag is set, otherwise false
  372. if (self->m_mipmap) Py_RETURN_TRUE;
  373. else Py_RETURN_FALSE;
  374. }
  375. // set mipmap value
  376. static int Texture_setMipmap(Texture *self, PyObject *value, void *closure)
  377. {
  378. // check parameter, report failure
  379. if (value == NULL || !PyBool_Check(value))
  380. {
  381. PyErr_SetString(PyExc_TypeError, "The value must be a bool");
  382. return -1;
  383. }
  384. // set mipmap
  385. self->m_mipmap = value == Py_True;
  386. // success
  387. return 0;
  388. }
  389. // get source object
  390. static PyObject *Texture_getSource(Texture *self, PyObject *value, void *closure)
  391. {
  392. // if source exists
  393. if (self->m_source != NULL)
  394. {
  395. Py_INCREF(self->m_source);
  396. return reinterpret_cast<PyObject*>(self->m_source);
  397. }
  398. // otherwise return None
  399. Py_RETURN_NONE;
  400. }
  401. // set source object
  402. int Texture_setSource(Texture *self, PyObject *value, void *closure)
  403. {
  404. // check new value
  405. if (value == NULL || !pyImageTypes.in(Py_TYPE(value)))
  406. {
  407. // report value error
  408. PyErr_SetString(PyExc_TypeError, "Invalid type of value");
  409. return -1;
  410. }
  411. // increase ref count for new value
  412. Py_INCREF(value);
  413. // release previous
  414. Py_XDECREF(self->m_source);
  415. // set new value
  416. self->m_source = reinterpret_cast<PyImage*>(value);
  417. // return success
  418. return 0;
  419. }
  420. // class Texture methods
  421. static PyMethodDef textureMethods[] =
  422. {
  423. { "close", (PyCFunction)Texture_close, METH_NOARGS, "Close dynamic texture and restore original"},
  424. { "refresh", (PyCFunction)Texture_refresh, METH_VARARGS, "Refresh texture from source"},
  425. {NULL} /* Sentinel */
  426. };
  427. // class Texture attributes
  428. static PyGetSetDef textureGetSets[] =
  429. {
  430. {(char*)"source", (getter)Texture_getSource, (setter)Texture_setSource, (char*)"source of texture", NULL},
  431. {(char*)"mipmap", (getter)Texture_getMipmap, (setter)Texture_setMipmap, (char*)"mipmap texture", NULL},
  432. {(char*)"bindId", (getter)Texture_getBindId, NULL, (char*)"OpenGL Bind Name", NULL},
  433. {NULL}
  434. };
  435. // class Texture declaration
  436. PyTypeObject TextureType =
  437. {
  438. PyVarObject_HEAD_INIT(NULL, 0)
  439. "VideoTexture.Texture", /*tp_name*/
  440. sizeof(Texture), /*tp_basicsize*/
  441. 0, /*tp_itemsize*/
  442. (destructor)Texture_dealloc,/*tp_dealloc*/
  443. 0, /*tp_print*/
  444. 0, /*tp_getattr*/
  445. 0, /*tp_setattr*/
  446. 0, /*tp_compare*/
  447. 0, /*tp_repr*/
  448. 0, /*tp_as_number*/
  449. 0, /*tp_as_sequence*/
  450. 0, /*tp_as_mapping*/
  451. 0, /*tp_hash */
  452. 0, /*tp_call*/
  453. 0, /*tp_str*/
  454. 0, /*tp_getattro*/
  455. 0, /*tp_setattro*/
  456. &imageBufferProcs, /*tp_as_buffer*/
  457. Py_TPFLAGS_DEFAULT, /*tp_flags*/
  458. "Texture objects", /* tp_doc */
  459. 0, /* tp_traverse */
  460. 0, /* tp_clear */
  461. 0, /* tp_richcompare */
  462. 0, /* tp_weaklistoffset */
  463. 0, /* tp_iter */
  464. 0, /* tp_iternext */
  465. textureMethods, /* tp_methods */
  466. 0, /* tp_members */
  467. textureGetSets, /* tp_getset */
  468. 0, /* tp_base */
  469. 0, /* tp_dict */
  470. 0, /* tp_descr_get */
  471. 0, /* tp_descr_set */
  472. 0, /* tp_dictoffset */
  473. (initproc)Texture_init, /* tp_init */
  474. 0, /* tp_alloc */
  475. Texture_new, /* tp_new */
  476. };