3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "mapblock_mesh.h"
24 #include "main.h" // For g_settings and g_texturesource
29 #include "content_mapblock.h"
30 #include "mineral.h" // For mineral_block_texture
32 void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
34 m_daynight_ratio = daynight_ratio;
35 m_blockpos = block->getPos();
37 v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
40 There is no harm not copying the TempMods of the neighbors
41 because they are already copied to this block
44 block->copyTempMods(m_temp_mods);
50 // Allocate this block + neighbors
52 m_vmanip.addArea(VoxelArea(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
53 blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1)));
56 //TimeTaker timer("copy central block data");
60 block->copyTo(m_vmanip);
63 //TimeTaker timer("copy neighbor block data");
67 Copy neighbors. This is lightning fast.
68 Copying only the borders would be *very* slow.
72 Map *map = block->getParent();
74 for(u16 i=0; i<6; i++)
76 const v3s16 &dir = g_6dirs[i];
77 v3s16 bp = m_blockpos + dir;
78 MapBlock *b = map->getBlockNoCreateNoEx(bp);
85 void MeshMakeData::fillSingleNode(u32 daynight_ratio, MapNode *node)
87 m_daynight_ratio = daynight_ratio;
88 m_blockpos = v3s16(0,0,0);
91 v3s16 blockpos_nodes = v3s16(0,0,0);
92 VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
93 blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
94 s32 volume = area.getVolume();
95 s32 our_node_index = area.index(1,1,1);
97 // Allocate this block + neighbors
99 m_vmanip.addArea(area);
102 MapNode *data = new MapNode[volume];
103 for(s32 i = 0; i < volume; i++)
105 if(i == our_node_index)
111 data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
114 m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
119 vertex_dirs: v3s16[4]
121 static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
124 If looked from outside the node towards the face, the corners are:
130 if(dir == v3s16(0,0,1))
132 // If looking towards z+, this is the face that is behind
133 // the center point, facing towards z+.
134 vertex_dirs[0] = v3s16(-1,-1, 1);
135 vertex_dirs[1] = v3s16( 1,-1, 1);
136 vertex_dirs[2] = v3s16( 1, 1, 1);
137 vertex_dirs[3] = v3s16(-1, 1, 1);
139 else if(dir == v3s16(0,0,-1))
142 vertex_dirs[0] = v3s16( 1,-1,-1);
143 vertex_dirs[1] = v3s16(-1,-1,-1);
144 vertex_dirs[2] = v3s16(-1, 1,-1);
145 vertex_dirs[3] = v3s16( 1, 1,-1);
147 else if(dir == v3s16(1,0,0))
150 vertex_dirs[0] = v3s16( 1,-1, 1);
151 vertex_dirs[1] = v3s16( 1,-1,-1);
152 vertex_dirs[2] = v3s16( 1, 1,-1);
153 vertex_dirs[3] = v3s16( 1, 1, 1);
155 else if(dir == v3s16(-1,0,0))
158 vertex_dirs[0] = v3s16(-1,-1,-1);
159 vertex_dirs[1] = v3s16(-1,-1, 1);
160 vertex_dirs[2] = v3s16(-1, 1, 1);
161 vertex_dirs[3] = v3s16(-1, 1,-1);
163 else if(dir == v3s16(0,1,0))
165 // faces towards Y+ (assume Z- as "down" in texture)
166 vertex_dirs[0] = v3s16( 1, 1,-1);
167 vertex_dirs[1] = v3s16(-1, 1,-1);
168 vertex_dirs[2] = v3s16(-1, 1, 1);
169 vertex_dirs[3] = v3s16( 1, 1, 1);
171 else if(dir == v3s16(0,-1,0))
173 // faces towards Y- (assume Z+ as "down" in texture)
174 vertex_dirs[0] = v3s16( 1,-1, 1);
175 vertex_dirs[1] = v3s16(-1,-1, 1);
176 vertex_dirs[2] = v3s16(-1,-1,-1);
177 vertex_dirs[3] = v3s16( 1,-1,-1);
181 video::SColor MapBlock_LightColor(u8 alpha, u8 light)
184 return video::SColor(alpha,light,light,light);
186 //return video::SColor(alpha,light,light,MYMAX(0, (s16)light-25)+25);
187 /*return video::SColor(alpha,light,light,MYMAX(0,
188 pow((float)light/255.0, 0.8)*255.0));*/
190 // Emphase blue a bit in darker places
194 return video::SColor(alpha,light,light,light);
196 return video::SColor(alpha,light,light,MYMAX(0,
197 pow((float)light/lim, power)*lim));
204 video::S3DVertex vertices[4]; // Precalculated vertices
207 static void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
208 v3s16 dir, v3f scale, v3f posRelative_f,
209 core::array<FastFace> &dest)
213 // Position is at the center of the cube.
218 v3s16 vertex_dirs[4];
219 getNodeVertexDirs(dir, vertex_dirs);
220 for(u16 i=0; i<4; i++)
223 BS/2*vertex_dirs[i].X,
224 BS/2*vertex_dirs[i].Y,
225 BS/2*vertex_dirs[i].Z
229 for(u16 i=0; i<4; i++)
231 vertex_pos[i].X *= scale.X;
232 vertex_pos[i].Y *= scale.Y;
233 vertex_pos[i].Z *= scale.Z;
234 vertex_pos[i] += pos + posRelative_f;
238 if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
239 else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
240 else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
242 v3f normal(dir.X, dir.Y, dir.Z);
244 u8 alpha = tile.alpha;
246 if(tile.id == TILE_WATER)
247 alpha = WATER_ALPHA;*/
249 float x0 = tile.texture.pos.X;
250 float y0 = tile.texture.pos.Y;
251 float w = tile.texture.size.X;
252 float h = tile.texture.size.Y;
254 /*video::SColor c = MapBlock_LightColor(alpha, li);
256 face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0), c,
257 core::vector2d<f32>(x0+w*abs_scale, y0+h));
258 face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0), c,
259 core::vector2d<f32>(x0, y0+h));
260 face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0), c,
261 core::vector2d<f32>(x0, y0));
262 face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), c,
263 core::vector2d<f32>(x0+w*abs_scale, y0));*/
265 face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
266 MapBlock_LightColor(alpha, li0),
267 core::vector2d<f32>(x0+w*abs_scale, y0+h));
268 face.vertices[1] = video::S3DVertex(vertex_pos[1], normal,
269 MapBlock_LightColor(alpha, li1),
270 core::vector2d<f32>(x0, y0+h));
271 face.vertices[2] = video::S3DVertex(vertex_pos[2], normal,
272 MapBlock_LightColor(alpha, li2),
273 core::vector2d<f32>(x0, y0));
274 face.vertices[3] = video::S3DVertex(vertex_pos[3], normal,
275 MapBlock_LightColor(alpha, li3),
276 core::vector2d<f32>(x0+w*abs_scale, y0));
280 //f->tile = TILE_STONE;
282 dest.push_back(face);
285 static TileSpec getTile(const MapNode &node, v3s16 dir,
286 ITextureSource *tsrc, INodeDefManager *nodemgr)
288 const ContentFeatures &f = nodemgr->get(node);
290 if(f.param_type == CPT_FACEDIR_SIMPLE)
291 dir = facedir_rotate(node.param1, dir);
297 if(dir == v3s16(0,0,0))
299 else if(dir == v3s16(0,1,0))
301 else if(dir == v3s16(0,-1,0))
303 else if(dir == v3s16(1,0,0))
305 else if(dir == v3s16(-1,0,0))
307 else if(dir == v3s16(0,0,1))
309 else if(dir == v3s16(0,0,-1))
316 spec = f.tiles[dir_i];
319 If it contains some mineral, change texture id
321 if(f.param_type == CPT_MINERAL && tsrc)
323 u8 mineral = node.getMineral(nodemgr);
324 std::string mineral_texture_name = mineral_block_texture(mineral);
325 if(mineral_texture_name != "")
327 u32 orig_id = spec.texture.id;
328 std::string texture_name = tsrc->getTextureName(orig_id);
329 //texture_name += "^blit:";
331 texture_name += mineral_texture_name;
332 u32 new_id = tsrc->getTextureId(texture_name);
333 spec.texture = tsrc->getTexture(new_id);
341 Gets node tile from any place relative to block.
342 Returns TILE_NODE if doesn't exist or should not be drawn.
344 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
345 NodeModMap *temp_mods, ITextureSource *tsrc, INodeDefManager *ndef)
348 spec = getTile(mn, face_dir, tsrc, ndef);
351 Check temporary modifications on this node
353 /*core::map<v3s16, NodeMod>::Node *n;
354 n = m_temp_mods.find(p);
358 struct NodeMod mod = n->getValue();*/
360 if(temp_mods && temp_mods->get(p, &mod))
362 #if 0 // NODEMOD_CHANGECONTENT isn't used at the moment
363 if(mod.type == NODEMOD_CHANGECONTENT)
365 MapNode mn2(mod.param);
366 spec = getTile(mn2, face_dir, tsrc, ndef);
369 if(mod.type == NODEMOD_CRACK)
372 Get texture id, translate it to name, append stuff to
376 // Get original texture name
377 u32 orig_id = spec.texture.id;
378 std::string orig_name = tsrc->getTextureName(orig_id);
380 // Create new texture name
381 std::ostringstream os;
382 os<<orig_name<<"^[crack"<<mod.param;
385 u32 new_id = tsrc->getTextureId(os.str());
387 /*dstream<<"MapBlock::getNodeTile(): Switching from "
388 <<orig_name<<" to "<<os.str()<<" ("
389 <<orig_id<<" to "<<new_id<<")"<<std::endl;*/
391 spec.texture = tsrc->getTexture(new_id);
398 static content_t getNodeContent(v3s16 p, MapNode mn, NodeModMap *temp_mods)
401 Check temporary modifications on this node
403 #if 0 // NODEMOD_CHANGECONTENT isn't used at the moment
405 if(temp_mods && temp_mods->get(p, &mod))
407 if(mod.type == NODEMOD_CHANGECONTENT)
412 if(mod.type == NODEMOD_CRACK)
415 Content doesn't change.
417 face_contents works just like it should, because
418 there should not be faces between differently cracked
421 If a semi-transparent node is cracked in front an
422 another one, it really doesn't matter whether there
423 is a cracked face drawn in between or not.
429 return mn.getContent();
443 // Calculate lighting at the XYZ- corner of p
444 static u8 getSmoothLight(v3s16 p, VoxelManipulator &vmanip, u32 daynight_ratio,
445 INodeDefManager *ndef)
447 u16 ambient_occlusion = 0;
450 for(u32 i=0; i<8; i++)
452 MapNode n = vmanip.getNodeNoEx(p - dirs8[i]);
453 if(ndef->get(n).param_type == CPT_LIGHT
454 // Fast-style leaves look better this way
455 && ndef->get(n).solidness != 2)
457 light += decode_light(n.getLightBlend(daynight_ratio, ndef));
462 if(n.getContent() != CONTENT_IGNORE)
470 light /= light_count;
472 if(ambient_occlusion > 4)
474 ambient_occlusion -= 4;
475 light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0);
481 // Calculate lighting at the given corner of p
482 static u8 getSmoothLight(v3s16 p, v3s16 corner,
483 VoxelManipulator &vmanip, u32 daynight_ratio, INodeDefManager *ndef)
485 if(corner.X == 1) p.X += 1;
486 else assert(corner.X == -1);
487 if(corner.Y == 1) p.Y += 1;
488 else assert(corner.Y == -1);
489 if(corner.Z == 1) p.Z += 1;
490 else assert(corner.Z == -1);
492 return getSmoothLight(p, vmanip, daynight_ratio, ndef);
495 static void getTileInfo(
497 v3s16 blockpos_nodes,
501 VoxelManipulator &vmanip,
502 NodeModMap *temp_mods,
503 bool smooth_lighting,
508 v3s16 &face_dir_corrected,
513 ITextureSource *tsrc = gamedef->tsrc();
514 INodeDefManager *ndef = gamedef->ndef();
516 MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
517 MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
518 TileSpec tile0 = getNodeTile(n0, p, face_dir, temp_mods, tsrc, ndef);
519 TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, temp_mods, tsrc, ndef);
522 content_t content0 = getNodeContent(p, n0, temp_mods);
523 content_t content1 = getNodeContent(p + face_dir, n1, temp_mods);
524 bool equivalent = false;
525 u8 mf = face_contents(content0, content1, &equivalent, ndef);
539 face_dir_corrected = face_dir;
544 p_corrected = p + face_dir;
545 face_dir_corrected = -face_dir;
548 // eg. water and glass
550 tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
552 if(smooth_lighting == false)
554 lights[0] = lights[1] = lights[2] = lights[3] =
555 decode_light(getFaceLight(daynight_ratio, n0, n1, face_dir, ndef));
559 v3s16 vertex_dirs[4];
560 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
561 for(u16 i=0; i<4; i++)
563 lights[i] = getSmoothLight(blockpos_nodes + p_corrected,
564 vertex_dirs[i], vmanip, daynight_ratio, ndef);
573 translate_dir: unit vector with only one of x, y or z
574 face_dir: unit vector with only one of x, y or z
576 static void updateFastFaceRow(
585 core::array<FastFace> &dest,
586 NodeModMap *temp_mods,
587 VoxelManipulator &vmanip,
588 v3s16 blockpos_nodes,
589 bool smooth_lighting,
594 u16 continuous_tiles_count = 0;
596 bool makes_face = false;
598 v3s16 face_dir_corrected;
599 u8 lights[4] = {0,0,0,0};
601 getTileInfo(blockpos_nodes, p, face_dir, daynight_ratio,
602 vmanip, temp_mods, smooth_lighting, gamedef,
603 makes_face, p_corrected, face_dir_corrected, lights, tile);
605 for(u16 j=0; j<length; j++)
607 // If tiling can be done, this is set to false in the next step
608 bool next_is_different = true;
612 bool next_makes_face = false;
613 v3s16 next_p_corrected;
614 v3s16 next_face_dir_corrected;
615 u8 next_lights[4] = {0,0,0,0};
618 // If at last position, there is nothing to compare to and
619 // the face must be drawn anyway
622 p_next = p + translate_dir;
624 getTileInfo(blockpos_nodes, p_next, face_dir, daynight_ratio,
625 vmanip, temp_mods, smooth_lighting, gamedef,
626 next_makes_face, next_p_corrected,
627 next_face_dir_corrected, next_lights,
630 if(next_makes_face == makes_face
631 && next_p_corrected == p_corrected + translate_dir
632 && next_face_dir_corrected == face_dir_corrected
633 && next_lights[0] == lights[0]
634 && next_lights[1] == lights[1]
635 && next_lights[2] == lights[2]
636 && next_lights[3] == lights[3]
637 && next_tile == tile)
639 next_is_different = false;
643 g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
644 next_makes_face != makes_face ? 1 : 0);
645 g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
646 (next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
647 g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
648 next_face_dir_corrected != face_dir_corrected ? 1 : 0);
649 g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
650 (next_lights[0] != lights[0] ||
651 next_lights[0] != lights[0] ||
652 next_lights[0] != lights[0] ||
653 next_lights[0] != lights[0]) ? 1 : 0);
654 g_profiler->add("Meshgen: diff: !(next_tile == tile)",
655 !(next_tile == tile) ? 1 : 0);
658 /*g_profiler->add("Meshgen: Total faces checked", 1);
660 g_profiler->add("Meshgen: Total makes_face checked", 1);*/
663 g_profiler->add("Meshgen: diff: last position", 1);*/
666 continuous_tiles_count++;
668 // This is set to true if the texture doesn't allow more tiling
669 bool end_of_texture = false;
671 If there is no texture, it can be tiled infinitely.
672 If tiled==0, it means the texture can be tiled infinitely.
673 Otherwise check tiled agains continuous_tiles_count.
675 if(tile.texture.atlas != NULL && tile.texture.tiled != 0)
677 if(tile.texture.tiled <= continuous_tiles_count)
678 end_of_texture = true;
681 // Do this to disable tiling textures
682 //end_of_texture = true; //DEBUG
684 if(next_is_different || end_of_texture)
687 Create a face if there should be one
691 // Floating point conversion of the position vector
692 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
693 // Center point of face (kind of)
694 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
695 if(continuous_tiles_count != 1)
696 sp += translate_dir_f;
699 if(translate_dir.X != 0)
701 scale.X = continuous_tiles_count;
703 if(translate_dir.Y != 0)
705 scale.Y = continuous_tiles_count;
707 if(translate_dir.Z != 0)
709 scale.Z = continuous_tiles_count;
712 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
713 sp, face_dir_corrected, scale,
714 posRelative_f, dest);
716 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
717 for(int i=1; i<continuous_tiles_count; i++){
718 g_profiler->avg("Meshgen: faces drawn by tiling", 1);
722 continuous_tiles_count = 0;
724 makes_face = next_makes_face;
725 p_corrected = next_p_corrected;
726 face_dir_corrected = next_face_dir_corrected;
727 lights[0] = next_lights[0];
728 lights[1] = next_lights[1];
729 lights[2] = next_lights[2];
730 lights[3] = next_lights[3];
738 scene::SMesh* makeMapBlockMesh(MeshMakeData *data, IGameDef *gamedef)
740 // 4-21ms for MAP_BLOCKSIZE=16
741 // 24-155ms for MAP_BLOCKSIZE=32
742 //TimeTaker timer1("makeMapBlockMesh()");
744 core::array<FastFace> fastfaces_new;
746 v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;
748 // floating point conversion
749 v3f posRelative_f(blockpos_nodes.X, blockpos_nodes.Y, blockpos_nodes.Z);
754 //bool new_style_water = g_settings->getBool("new_style_water");
755 //bool new_style_leaves = g_settings->getBool("new_style_leaves");
756 bool smooth_lighting = g_settings->getBool("smooth_lighting");
759 We are including the faces of the trailing edges of the block.
760 This means that when something changes, the caller must
761 also update the meshes of the blocks at the leading edges.
763 NOTE: This is the slowest part of this method.
767 // 4-23ms for MAP_BLOCKSIZE=16
768 //TimeTaker timer2("updateMesh() collect");
771 Go through every y,z and get top(y+) faces in rows of x+
773 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
774 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
775 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
776 v3s16(0,y,z), MAP_BLOCKSIZE,
779 v3s16(0,1,0), //face dir
790 Go through every x,y and get right(x+) faces in rows of z+
792 for(s16 x=0; x<MAP_BLOCKSIZE; x++){
793 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
794 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
795 v3s16(x,y,0), MAP_BLOCKSIZE,
809 Go through every y,z and get back(z+) faces in rows of x+
811 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
812 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
813 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
814 v3s16(0,y,z), MAP_BLOCKSIZE,
832 Convert FastFaces to SMesh
835 MeshCollector collector;
837 if(fastfaces_new.size() > 0)
839 // avg 0ms (100ms spikes when loading textures the first time)
840 //TimeTaker timer2("updateMesh() mesh building");
842 video::SMaterial material;
843 material.setFlag(video::EMF_LIGHTING, false);
844 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
845 material.setFlag(video::EMF_BILINEAR_FILTER, false);
846 material.setFlag(video::EMF_FOG_ENABLE, true);
847 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
848 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
849 material.MaterialType
850 = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
852 for(u32 i=0; i<fastfaces_new.size(); i++)
854 FastFace &f = fastfaces_new[i];
856 const u16 indices[] = {0,1,2,2,3,0};
857 const u16 indices_alternate[] = {0,1,3,2,3,1};
859 video::ITexture *texture = f.tile.texture.atlas;
863 material.setTexture(0, texture);
865 f.tile.applyMaterialOptions(material);
867 const u16 *indices_p = indices;
870 Revert triangles for nicer looking gradient if vertices
871 1 and 3 have same color or 0 and 2 have different color.
873 if(f.vertices[0].Color != f.vertices[2].Color
874 || f.vertices[1].Color == f.vertices[3].Color)
875 indices_p = indices_alternate;
877 collector.append(material, f.vertices, 4, indices_p, 6);
882 Add special graphics:
889 mapblock_mesh_generate_special(data, collector, gamedef);
892 Add stuff from collector to mesh
895 scene::SMesh *mesh_new = NULL;
896 mesh_new = new scene::SMesh();
898 collector.fillMesh(mesh_new);
901 Do some stuff to the mesh
904 mesh_new->recalculateBoundingBox();
907 Delete new mesh if it is empty
910 if(mesh_new->getMeshBufferCount() == 0)
919 // Usually 1-700 faces and 1-7 materials
920 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
921 <<"and uses "<<mesh_new->getMeshBufferCount()
922 <<" materials (meshbuffers)"<<std::endl;
925 // Use VBO for mesh (this just would set this for ever buffer)
926 // This will lead to infinite memory usage because or irrlicht.
927 //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
930 NOTE: If that is enabled, some kind of a queue to the main
931 thread should be made which would call irrlicht to delete
932 the hardware buffer and then delete the mesh
938 //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;