wieldmesh.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. /*
  2. Minetest
  3. Copyright (C) 2010-2014 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "settings.h"
  17. #include "wieldmesh.h"
  18. #include "inventory.h"
  19. #include "gamedef.h"
  20. #include "itemdef.h"
  21. #include "nodedef.h"
  22. #include "mesh.h"
  23. #include "mapblock_mesh.h"
  24. #include "client/tile.h"
  25. #include "log.h"
  26. #include "util/numeric.h"
  27. #include <map>
  28. #include <IMeshManipulator.h>
  29. #define WIELD_SCALE_FACTOR 30.0
  30. #define WIELD_SCALE_FACTOR_EXTRUDED 40.0
  31. #define MIN_EXTRUSION_MESH_RESOLUTION 16
  32. #define MAX_EXTRUSION_MESH_RESOLUTION 512
  33. static scene::IMesh *createExtrusionMesh(int resolution_x, int resolution_y)
  34. {
  35. const f32 r = 0.5;
  36. scene::IMeshBuffer *buf = new scene::SMeshBuffer();
  37. video::SColor c(255,255,255,255);
  38. v3f scale(1.0, 1.0, 0.1);
  39. // Front and back
  40. {
  41. video::S3DVertex vertices[8] = {
  42. // z-
  43. video::S3DVertex(-r,+r,-r, 0,0,-1, c, 0,0),
  44. video::S3DVertex(+r,+r,-r, 0,0,-1, c, 1,0),
  45. video::S3DVertex(+r,-r,-r, 0,0,-1, c, 1,1),
  46. video::S3DVertex(-r,-r,-r, 0,0,-1, c, 0,1),
  47. // z+
  48. video::S3DVertex(-r,+r,+r, 0,0,+1, c, 0,0),
  49. video::S3DVertex(-r,-r,+r, 0,0,+1, c, 0,1),
  50. video::S3DVertex(+r,-r,+r, 0,0,+1, c, 1,1),
  51. video::S3DVertex(+r,+r,+r, 0,0,+1, c, 1,0),
  52. };
  53. u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4};
  54. buf->append(vertices, 8, indices, 12);
  55. }
  56. f32 pixelsize_x = 1 / (f32) resolution_x;
  57. f32 pixelsize_y = 1 / (f32) resolution_y;
  58. for (int i = 0; i < resolution_x; ++i) {
  59. f32 pixelpos_x = i * pixelsize_x - 0.5;
  60. f32 x0 = pixelpos_x;
  61. f32 x1 = pixelpos_x + pixelsize_x;
  62. f32 tex0 = (i + 0.1) * pixelsize_x;
  63. f32 tex1 = (i + 0.9) * pixelsize_x;
  64. video::S3DVertex vertices[8] = {
  65. // x-
  66. video::S3DVertex(x0,-r,-r, -1,0,0, c, tex0,1),
  67. video::S3DVertex(x0,-r,+r, -1,0,0, c, tex1,1),
  68. video::S3DVertex(x0,+r,+r, -1,0,0, c, tex1,0),
  69. video::S3DVertex(x0,+r,-r, -1,0,0, c, tex0,0),
  70. // x+
  71. video::S3DVertex(x1,-r,-r, +1,0,0, c, tex0,1),
  72. video::S3DVertex(x1,+r,-r, +1,0,0, c, tex0,0),
  73. video::S3DVertex(x1,+r,+r, +1,0,0, c, tex1,0),
  74. video::S3DVertex(x1,-r,+r, +1,0,0, c, tex1,1),
  75. };
  76. u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4};
  77. buf->append(vertices, 8, indices, 12);
  78. }
  79. for (int i = 0; i < resolution_y; ++i) {
  80. f32 pixelpos_y = i * pixelsize_y - 0.5;
  81. f32 y0 = -pixelpos_y - pixelsize_y;
  82. f32 y1 = -pixelpos_y;
  83. f32 tex0 = (i + 0.1) * pixelsize_y;
  84. f32 tex1 = (i + 0.9) * pixelsize_y;
  85. video::S3DVertex vertices[8] = {
  86. // y-
  87. video::S3DVertex(-r,y0,-r, 0,-1,0, c, 0,tex0),
  88. video::S3DVertex(+r,y0,-r, 0,-1,0, c, 1,tex0),
  89. video::S3DVertex(+r,y0,+r, 0,-1,0, c, 1,tex1),
  90. video::S3DVertex(-r,y0,+r, 0,-1,0, c, 0,tex1),
  91. // y+
  92. video::S3DVertex(-r,y1,-r, 0,+1,0, c, 0,tex0),
  93. video::S3DVertex(-r,y1,+r, 0,+1,0, c, 0,tex1),
  94. video::S3DVertex(+r,y1,+r, 0,+1,0, c, 1,tex1),
  95. video::S3DVertex(+r,y1,-r, 0,+1,0, c, 1,tex0),
  96. };
  97. u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4};
  98. buf->append(vertices, 8, indices, 12);
  99. }
  100. // Create mesh object
  101. scene::SMesh *mesh = new scene::SMesh();
  102. mesh->addMeshBuffer(buf);
  103. buf->drop();
  104. scaleMesh(mesh, scale); // also recalculates bounding box
  105. return mesh;
  106. }
  107. /*
  108. Caches extrusion meshes so that only one of them per resolution
  109. is needed. Also caches one cube (for convenience).
  110. E.g. there is a single extrusion mesh that is used for all
  111. 16x16 px images, another for all 256x256 px images, and so on.
  112. WARNING: Not thread safe. This should not be a problem since
  113. rendering related classes (such as WieldMeshSceneNode) will be
  114. used from the rendering thread only.
  115. */
  116. class ExtrusionMeshCache: public IReferenceCounted
  117. {
  118. public:
  119. // Constructor
  120. ExtrusionMeshCache()
  121. {
  122. for (int resolution = MIN_EXTRUSION_MESH_RESOLUTION;
  123. resolution <= MAX_EXTRUSION_MESH_RESOLUTION;
  124. resolution *= 2) {
  125. m_extrusion_meshes[resolution] =
  126. createExtrusionMesh(resolution, resolution);
  127. }
  128. m_cube = createCubeMesh(v3f(1.0, 1.0, 1.0));
  129. }
  130. // Destructor
  131. virtual ~ExtrusionMeshCache()
  132. {
  133. for (std::map<int, scene::IMesh*>::iterator
  134. it = m_extrusion_meshes.begin();
  135. it != m_extrusion_meshes.end(); ++it) {
  136. it->second->drop();
  137. }
  138. m_cube->drop();
  139. }
  140. // Get closest extrusion mesh for given image dimensions
  141. // Caller must drop the returned pointer
  142. scene::IMesh* create(core::dimension2d<u32> dim)
  143. {
  144. // handle non-power of two textures inefficiently without cache
  145. if (!is_power_of_two(dim.Width) || !is_power_of_two(dim.Height)) {
  146. return createExtrusionMesh(dim.Width, dim.Height);
  147. }
  148. int maxdim = MYMAX(dim.Width, dim.Height);
  149. std::map<int, scene::IMesh*>::iterator
  150. it = m_extrusion_meshes.lower_bound(maxdim);
  151. if (it == m_extrusion_meshes.end()) {
  152. // no viable resolution found; use largest one
  153. it = m_extrusion_meshes.find(MAX_EXTRUSION_MESH_RESOLUTION);
  154. sanity_check(it != m_extrusion_meshes.end());
  155. }
  156. scene::IMesh *mesh = it->second;
  157. mesh->grab();
  158. return mesh;
  159. }
  160. // Returns a 1x1x1 cube mesh with one meshbuffer (material) per face
  161. // Caller must drop the returned pointer
  162. scene::IMesh* createCube()
  163. {
  164. m_cube->grab();
  165. return m_cube;
  166. }
  167. private:
  168. std::map<int, scene::IMesh*> m_extrusion_meshes;
  169. scene::IMesh *m_cube;
  170. };
  171. ExtrusionMeshCache *g_extrusion_mesh_cache = NULL;
  172. WieldMeshSceneNode::WieldMeshSceneNode(
  173. scene::ISceneNode *parent,
  174. scene::ISceneManager *mgr,
  175. s32 id,
  176. bool lighting
  177. ):
  178. scene::ISceneNode(parent, mgr, id),
  179. m_meshnode(NULL),
  180. m_material_type(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF),
  181. m_lighting(lighting),
  182. m_bounding_box(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
  183. {
  184. m_enable_shaders = g_settings->getBool("enable_shaders");
  185. m_anisotropic_filter = g_settings->getBool("anisotropic_filter");
  186. m_bilinear_filter = g_settings->getBool("bilinear_filter");
  187. m_trilinear_filter = g_settings->getBool("trilinear_filter");
  188. // If this is the first wield mesh scene node, create a cache
  189. // for extrusion meshes (and a cube mesh), otherwise reuse it
  190. if (g_extrusion_mesh_cache == NULL)
  191. g_extrusion_mesh_cache = new ExtrusionMeshCache();
  192. else
  193. g_extrusion_mesh_cache->grab();
  194. // Disable bounding box culling for this scene node
  195. // since we won't calculate the bounding box.
  196. setAutomaticCulling(scene::EAC_OFF);
  197. // Create the child scene node
  198. scene::IMesh *dummymesh = g_extrusion_mesh_cache->createCube();
  199. m_meshnode = SceneManager->addMeshSceneNode(dummymesh, this, -1);
  200. m_meshnode->setReadOnlyMaterials(false);
  201. m_meshnode->setVisible(false);
  202. dummymesh->drop(); // m_meshnode grabbed it
  203. }
  204. WieldMeshSceneNode::~WieldMeshSceneNode()
  205. {
  206. sanity_check(g_extrusion_mesh_cache);
  207. if (g_extrusion_mesh_cache->drop())
  208. g_extrusion_mesh_cache = NULL;
  209. }
  210. void WieldMeshSceneNode::setCube(const TileSpec tiles[6],
  211. v3f wield_scale, ITextureSource *tsrc)
  212. {
  213. scene::IMesh *cubemesh = g_extrusion_mesh_cache->createCube();
  214. changeToMesh(cubemesh);
  215. cubemesh->drop();
  216. m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR);
  217. // Customize materials
  218. for (u32 i = 0; i < m_meshnode->getMaterialCount(); ++i) {
  219. assert(i < 6);
  220. video::SMaterial &material = m_meshnode->getMaterial(i);
  221. if (tiles[i].animation_frame_count == 1) {
  222. material.setTexture(0, tiles[i].texture);
  223. } else {
  224. FrameSpec animation_frame = tiles[i].frames[0];
  225. material.setTexture(0, animation_frame.texture);
  226. }
  227. tiles[i].applyMaterialOptions(material);
  228. }
  229. }
  230. void WieldMeshSceneNode::setExtruded(const std::string &imagename,
  231. v3f wield_scale, ITextureSource *tsrc, u8 num_frames)
  232. {
  233. video::ITexture *texture = tsrc->getTexture(imagename);
  234. if (!texture) {
  235. changeToMesh(NULL);
  236. return;
  237. }
  238. core::dimension2d<u32> dim = texture->getSize();
  239. // Detect animation texture and pull off top frame instead of using entire thing
  240. if (num_frames > 1) {
  241. u32 frame_height = dim.Height / num_frames;
  242. dim = core::dimension2d<u32>(dim.Width, frame_height);
  243. }
  244. scene::IMesh *mesh = g_extrusion_mesh_cache->create(dim);
  245. changeToMesh(mesh);
  246. mesh->drop();
  247. m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR_EXTRUDED);
  248. // Customize material
  249. video::SMaterial &material = m_meshnode->getMaterial(0);
  250. material.setTexture(0, tsrc->getTextureForMesh(imagename));
  251. material.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
  252. material.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
  253. material.MaterialType = m_material_type;
  254. material.setFlag(video::EMF_BACK_FACE_CULLING, true);
  255. // Enable bi/trilinear filtering only for high resolution textures
  256. if (dim.Width > 32) {
  257. material.setFlag(video::EMF_BILINEAR_FILTER, m_bilinear_filter);
  258. material.setFlag(video::EMF_TRILINEAR_FILTER, m_trilinear_filter);
  259. } else {
  260. material.setFlag(video::EMF_BILINEAR_FILTER, false);
  261. material.setFlag(video::EMF_TRILINEAR_FILTER, false);
  262. }
  263. material.setFlag(video::EMF_ANISOTROPIC_FILTER, m_anisotropic_filter);
  264. // mipmaps cause "thin black line" artifacts
  265. #if (IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2
  266. material.setFlag(video::EMF_USE_MIP_MAPS, false);
  267. #endif
  268. if (m_enable_shaders) {
  269. material.setTexture(2, tsrc->getShaderFlagsTexture(false));
  270. }
  271. }
  272. void WieldMeshSceneNode::setItem(const ItemStack &item, IGameDef *gamedef)
  273. {
  274. ITextureSource *tsrc = gamedef->getTextureSource();
  275. IItemDefManager *idef = gamedef->getItemDefManager();
  276. IShaderSource *shdrsrc = gamedef->getShaderSource();
  277. INodeDefManager *ndef = gamedef->getNodeDefManager();
  278. const ItemDefinition &def = item.getDefinition(idef);
  279. const ContentFeatures &f = ndef->get(def.name);
  280. content_t id = ndef->getId(def.name);
  281. if (m_enable_shaders) {
  282. u32 shader_id = shdrsrc->getShader("wielded_shader", TILE_MATERIAL_BASIC, NDT_NORMAL);
  283. m_material_type = shdrsrc->getShaderInfo(shader_id).material;
  284. }
  285. // If wield_image is defined, it overrides everything else
  286. if (def.wield_image != "") {
  287. setExtruded(def.wield_image, def.wield_scale, tsrc, 1);
  288. return;
  289. }
  290. // Handle nodes
  291. // See also CItemDefManager::createClientCached()
  292. else if (def.type == ITEM_NODE) {
  293. if (f.mesh_ptr[0]) {
  294. // e.g. mesh nodes and nodeboxes
  295. changeToMesh(f.mesh_ptr[0]);
  296. // mesh_ptr[0] is pre-scaled by BS * f->visual_scale
  297. m_meshnode->setScale(
  298. def.wield_scale * WIELD_SCALE_FACTOR
  299. / (BS * f.visual_scale));
  300. } else if (f.drawtype == NDT_AIRLIKE) {
  301. changeToMesh(NULL);
  302. } else if (f.drawtype == NDT_PLANTLIKE) {
  303. setExtruded(tsrc->getTextureName(f.tiles[0].texture_id), def.wield_scale, tsrc, f.tiles[0].animation_frame_count);
  304. } else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES) {
  305. setCube(f.tiles, def.wield_scale, tsrc);
  306. } else {
  307. MeshMakeData mesh_make_data(gamedef, false);
  308. MapNode mesh_make_node(id, 255, 0);
  309. mesh_make_data.fillSingleNode(&mesh_make_node);
  310. MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0));
  311. changeToMesh(mapblock_mesh.getMesh());
  312. translateMesh(m_meshnode->getMesh(), v3f(-BS, -BS, -BS));
  313. m_meshnode->setScale(
  314. def.wield_scale * WIELD_SCALE_FACTOR
  315. / (BS * f.visual_scale));
  316. }
  317. u32 material_count = m_meshnode->getMaterialCount();
  318. if (material_count > 6) {
  319. errorstream << "WieldMeshSceneNode::setItem: Invalid material "
  320. "count " << material_count << ", truncating to 6" << std::endl;
  321. material_count = 6;
  322. }
  323. for (u32 i = 0; i < material_count; ++i) {
  324. video::SMaterial &material = m_meshnode->getMaterial(i);
  325. material.setFlag(video::EMF_BACK_FACE_CULLING, true);
  326. material.setFlag(video::EMF_BILINEAR_FILTER, m_bilinear_filter);
  327. material.setFlag(video::EMF_TRILINEAR_FILTER, m_trilinear_filter);
  328. bool animated = (f.tiles[i].animation_frame_count > 1);
  329. if (animated) {
  330. FrameSpec animation_frame = f.tiles[i].frames[0];
  331. material.setTexture(0, animation_frame.texture);
  332. } else {
  333. material.setTexture(0, f.tiles[i].texture);
  334. }
  335. material.MaterialType = m_material_type;
  336. if (m_enable_shaders) {
  337. if (f.tiles[i].normal_texture) {
  338. if (animated) {
  339. FrameSpec animation_frame = f.tiles[i].frames[0];
  340. material.setTexture(1, animation_frame.normal_texture);
  341. } else {
  342. material.setTexture(1, f.tiles[i].normal_texture);
  343. }
  344. }
  345. material.setTexture(2, f.tiles[i].flags_texture);
  346. }
  347. }
  348. return;
  349. }
  350. else if (def.inventory_image != "") {
  351. setExtruded(def.inventory_image, def.wield_scale, tsrc, 1);
  352. return;
  353. }
  354. // no wield mesh found
  355. changeToMesh(NULL);
  356. }
  357. void WieldMeshSceneNode::setColor(video::SColor color)
  358. {
  359. assert(!m_lighting);
  360. setMeshColor(m_meshnode->getMesh(), color);
  361. shadeMeshFaces(m_meshnode->getMesh());
  362. }
  363. void WieldMeshSceneNode::render()
  364. {
  365. // note: if this method is changed to actually do something,
  366. // you probably should implement OnRegisterSceneNode as well
  367. }
  368. void WieldMeshSceneNode::changeToMesh(scene::IMesh *mesh)
  369. {
  370. if (mesh == NULL) {
  371. scene::IMesh *dummymesh = g_extrusion_mesh_cache->createCube();
  372. m_meshnode->setVisible(false);
  373. m_meshnode->setMesh(dummymesh);
  374. dummymesh->drop(); // m_meshnode grabbed it
  375. } else {
  376. if (m_lighting) {
  377. m_meshnode->setMesh(mesh);
  378. } else {
  379. /*
  380. Lighting is disabled, this means the caller can (and probably will)
  381. call setColor later. We therefore need to clone the mesh so that
  382. setColor will only modify this scene node's mesh, not others'.
  383. */
  384. scene::IMeshManipulator *meshmanip = SceneManager->getMeshManipulator();
  385. scene::IMesh *new_mesh = meshmanip->createMeshCopy(mesh);
  386. m_meshnode->setMesh(new_mesh);
  387. new_mesh->drop(); // m_meshnode grabbed it
  388. }
  389. }
  390. m_meshnode->setMaterialFlag(video::EMF_LIGHTING, m_lighting);
  391. // need to normalize normals when lighting is enabled (because of setScale())
  392. m_meshnode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, m_lighting);
  393. m_meshnode->setVisible(true);
  394. }
  395. scene::IMesh *getItemMesh(IGameDef *gamedef, const ItemStack &item)
  396. {
  397. ITextureSource *tsrc = gamedef->getTextureSource();
  398. IItemDefManager *idef = gamedef->getItemDefManager();
  399. INodeDefManager *ndef = gamedef->getNodeDefManager();
  400. const ItemDefinition &def = item.getDefinition(idef);
  401. const ContentFeatures &f = ndef->get(def.name);
  402. content_t id = ndef->getId(def.name);
  403. if (!g_extrusion_mesh_cache) {
  404. g_extrusion_mesh_cache = new ExtrusionMeshCache();
  405. } else {
  406. g_extrusion_mesh_cache->grab();
  407. }
  408. scene::IMesh *mesh;
  409. // If inventory_image is defined, it overrides everything else
  410. if (def.inventory_image != "") {
  411. mesh = getExtrudedMesh(tsrc, def.inventory_image);
  412. return mesh;
  413. } else if (def.type == ITEM_NODE) {
  414. if (f.mesh_ptr[0]) {
  415. mesh = cloneMesh(f.mesh_ptr[0]);
  416. scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
  417. setMeshColor(mesh, video::SColor (255, 255, 255, 255));
  418. } else if (f.drawtype == NDT_PLANTLIKE) {
  419. mesh = getExtrudedMesh(tsrc,
  420. tsrc->getTextureName(f.tiles[0].texture_id));
  421. return mesh;
  422. } else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES
  423. || f.drawtype == NDT_LIQUID || f.drawtype == NDT_FLOWINGLIQUID) {
  424. mesh = cloneMesh(g_extrusion_mesh_cache->createCube());
  425. scaleMesh(mesh, v3f(1.2, 1.2, 1.2));
  426. } else {
  427. MeshMakeData mesh_make_data(gamedef, false);
  428. MapNode mesh_make_node(id, 255, 0);
  429. mesh_make_data.fillSingleNode(&mesh_make_node);
  430. MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0));
  431. mesh = cloneMesh(mapblock_mesh.getMesh());
  432. translateMesh(mesh, v3f(-BS, -BS, -BS));
  433. scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
  434. rotateMeshXZby(mesh, -45);
  435. rotateMeshYZby(mesh, -30);
  436. u32 mc = mesh->getMeshBufferCount();
  437. for (u32 i = 0; i < mc; ++i) {
  438. video::SMaterial &material1 =
  439. mesh->getMeshBuffer(i)->getMaterial();
  440. video::SMaterial &material2 =
  441. mapblock_mesh.getMesh()->getMeshBuffer(i)->getMaterial();
  442. material1.setTexture(0, material2.getTexture(0));
  443. material1.setTexture(1, material2.getTexture(1));
  444. material1.setTexture(2, material2.getTexture(2));
  445. material1.setTexture(3, material2.getTexture(3));
  446. material1.MaterialType = material2.MaterialType;
  447. }
  448. return mesh;
  449. }
  450. shadeMeshFaces(mesh);
  451. rotateMeshXZby(mesh, -45);
  452. rotateMeshYZby(mesh, -30);
  453. u32 mc = mesh->getMeshBufferCount();
  454. for (u32 i = 0; i < mc; ++i) {
  455. video::SMaterial &material = mesh->getMeshBuffer(i)->getMaterial();
  456. material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
  457. material.setFlag(video::EMF_BILINEAR_FILTER, false);
  458. material.setFlag(video::EMF_TRILINEAR_FILTER, false);
  459. material.setFlag(video::EMF_BACK_FACE_CULLING, true);
  460. material.setFlag(video::EMF_LIGHTING, false);
  461. if (f.tiles[i].animation_frame_count > 1) {
  462. FrameSpec animation_frame = f.tiles[i].frames[0];
  463. material.setTexture(0, animation_frame.texture);
  464. } else {
  465. material.setTexture(0, f.tiles[i].texture);
  466. }
  467. }
  468. return mesh;
  469. }
  470. return NULL;
  471. }
  472. scene::IMesh * getExtrudedMesh(ITextureSource *tsrc,
  473. const std::string &imagename)
  474. {
  475. video::ITexture *texture = tsrc->getTextureForMesh(imagename);
  476. if (!texture) {
  477. return NULL;
  478. }
  479. core::dimension2d<u32> dim = texture->getSize();
  480. scene::IMesh *mesh = cloneMesh(g_extrusion_mesh_cache->create(dim));
  481. // Customize material
  482. video::SMaterial &material = mesh->getMeshBuffer(0)->getMaterial();
  483. material.setTexture(0, tsrc->getTexture(imagename));
  484. material.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
  485. material.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
  486. material.setFlag(video::EMF_BILINEAR_FILTER, false);
  487. material.setFlag(video::EMF_TRILINEAR_FILTER, false);
  488. material.setFlag(video::EMF_BACK_FACE_CULLING, true);
  489. material.setFlag(video::EMF_LIGHTING, false);
  490. material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
  491. scaleMesh(mesh, v3f(2.0, 2.0, 2.0));
  492. return mesh;
  493. }