Пример #1
0
bool CSTLMeshWriter::writeMeshASCII(io::IWriteFile* file, scene::IMesh* mesh, s32 flags)
{
	// write STL MESH header

	file->write("solid ",6);
	const core::stringc name(SceneManager->getMeshCache()->getMeshName(mesh));
	file->write(name.c_str(),name.size());
	file->write("\n\n",2);

	// write mesh buffers

	for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
	{
		IMeshBuffer* buffer = mesh->getMeshBuffer(i);
		if (buffer)
		{
			const u32 indexCount = buffer->getIndexCount();
			for (u32 j=0; j<indexCount; j+=3)
			{
				writeFace(file,
					buffer->getPosition(buffer->getIndices()[j]),
					buffer->getPosition(buffer->getIndices()[j+1]),
					buffer->getPosition(buffer->getIndices()[j+2]));
			}
			file->write("\n",1);
		}
	}

	file->write("endsolid ",9);
	file->write(name.c_str(),name.size());

	return true;
}
Пример #2
0
f32 TerrainTile::getVerticeHeight(vector3df pos)
{
	f32 radius = 100;
	f32 returnvalue = 0;
	f32 smallest = radius;
	IMeshBuffer* meshBuffer = ((IMeshSceneNode*)node)->getMesh()->getMeshBuffer(0);

	S3DVertex* mb_vertices = (S3DVertex*) meshBuffer->getVertices();

	u16* mb_indices  = meshBuffer->getIndices();

	//Check all indices in the mesh to find the one that is nearest the position
	for (unsigned int j = 0; j < meshBuffer->getVertexCount(); j += 1)
	{
	    vector3df realPos = mb_vertices[j].Pos*(scale/nodescale) + node->getPosition();
        pos.Y = realPos.Y; //Put the height at the same height

		//Check if its the smallest distance
	    if((realPos.getDistanceFrom(pos) < smallest))
	    {
			smallest = realPos.getDistanceFrom(pos);
			returnvalue = realPos.Y;
	    }

	}
	return returnvalue;

}
Пример #3
0
void CTriangleSelector::updateFromMesh(const IMesh* mesh) const
{
    if (!mesh)
        return;

    u32 meshBuffers = mesh->getMeshBufferCount();
    u32 triangleCount = 0;

    BoundingBox.reset(0.f, 0.f, 0.f);
    for (u32 i = 0; i < meshBuffers; ++i)
    {
        IMeshBuffer* buf = mesh->getMeshBuffer(i);
        u32 idxCnt = buf->getIndexCount();
        const u16* indices = buf->getIndices();

        for (u32 index = 0; index < idxCnt; index += 3)
        {
            core::triangle3df& tri = Triangles[triangleCount++];
            tri.pointA = buf->getPosition(indices[index + 0]);
            tri.pointB = buf->getPosition(indices[index + 1]);
            tri.pointC = buf->getPosition(indices[index + 2]);
            BoundingBox.addInternalPoint(tri.pointA);
            BoundingBox.addInternalPoint(tri.pointB);
            BoundingBox.addInternalPoint(tri.pointC);
        }
    }
}
Пример #4
0
bool CSTLMeshWriter::writeMeshBinary(io::IWriteFile* file, scene::IMesh* mesh, s32 flags)
{
	// write STL MESH header

	file->write("binary ",7);
	const core::stringc name(SceneManager->getMeshCache()->getMeshName(mesh));
	const s32 sizeleft = 73-name.size(); // 80 byte header
	if (sizeleft<0)
		file->write(name.c_str(),73);
	else
	{
		char* buf = new char[80];
		memset(buf, 0, 80);
		file->write(name.c_str(),name.size());
		file->write(buf,sizeleft);
		delete [] buf;
	}
	u32 facenum = 0;
	for (u32 j=0; j<mesh->getMeshBufferCount(); ++j)
		facenum += mesh->getMeshBuffer(j)->getIndexCount()/3;
	file->write(&facenum,4);

	// write mesh buffers

	for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
	{
		IMeshBuffer* buffer = mesh->getMeshBuffer(i);
		if (buffer)
		{
			const u32 indexCount = buffer->getIndexCount();
			const u16 attributes = 0;
			for (u32 j=0; j<indexCount; j+=3)
			{
				const core::vector3df& v1 = buffer->getPosition(buffer->getIndices()[j]);
				const core::vector3df& v2 = buffer->getPosition(buffer->getIndices()[j+1]);
				const core::vector3df& v3 = buffer->getPosition(buffer->getIndices()[j+2]);
				const core::plane3df tmpplane(v1,v2,v3);
				file->write(&tmpplane.Normal, 12);
				file->write(&v1, 12);
				file->write(&v2, 12);
				file->write(&v3, 12);
				file->write(&attributes, 2);
			}
		}
	}
	return true;
}
Пример #5
0
    //-----------------------------------------------------------------------
    //                     e x t r a c t T r i a n g l e s
    //-----------------------------------------------------------------------
    btTriangleMesh* TMeshShape::extractTriangles(IMesh* mesh,   
        bool removeDupVertices)
    {
        vector3df p1, p2, p3;

        // 32 bit indices, 3 component vertices - allows for use in decomposition.
        btTriangleMesh* triMesh = new btTriangleMesh(true, false);
        u32 bufCount = mesh->getMeshBufferCount();

        for(u32 i=0;i<bufCount;i++)
        {
            IMeshBuffer* mbuf = mesh->getMeshBuffer(i);
            void* vp = mbuf->getVertices();
            E_VERTEX_TYPE vtype = mbuf->getVertexType();
            S3DVertex           *vstd = (S3DVertex*) vp;
            S3DVertex2TCoords   *v2t = (S3DVertex2TCoords*) vp;
            S3DVertexTangents   *vtan = (S3DVertexTangents*)vp;
            const u16* ip = mbuf->getIndices();
            u32 ic = mbuf->getIndexCount();
            u32 fi = 0;
            while(fi < ic)
            {
                S3DVertex *v1,*v2,*v3;
                switch(vtype)
                {
                case EVT_2TCOORDS:
                    v1 = &v2t[ip[fi++]];
                    v2 = &v2t[ip[fi++]];
                    v3 = &v2t[ip[fi++]];
                    break;
                case EVT_TANGENTS:
                    v1 = &vtan[ip[fi++]];
                    v2 = &vtan[ip[fi++]];
                    v3 = &vtan[ip[fi++]];
                    break;
                default:
                    v1 = &vstd[ip[fi++]];
                    v2 = &vstd[ip[fi++]];
                    v3 = &vstd[ip[fi++]];
                    break;
                }

                p1 = v1->Pos;
                p2 = v2->Pos;
                p3 = v3->Pos;

                btVector3 b1(p1.X, p1.Y, p1.Z);
                btVector3 b2(p2.X, p2.Y, p2.Z);
                btVector3 b3(p3.X, p3.Y, p3.Z);

                triMesh->addTriangle(b1,b2,b3,removeDupVertices);
            }
        }
        return triMesh;
    }
Пример #6
0
void CTriangleSelector::updateFromMesh(const IMesh* mesh) const
{
	if (!mesh)
		return;

	u32 meshBuffers = mesh->getMeshBufferCount();
	u32 triangleCount = 0;

	for (u32 i = 0; i < meshBuffers; ++i)
	{
		IMeshBuffer* buf = mesh->getMeshBuffer(i);
		u32 idxCnt = buf->getIndexCount();
		const u16* indices = buf->getIndices();

		switch (buf->getVertexType())
		{
		case video::EVT_STANDARD:
			{
				video::S3DVertex* vtx = (video::S3DVertex*)buf->getVertices();
				for (u32 index = 0; index < idxCnt; index += 3)
				{
					core::triangle3df & tri = Triangles[triangleCount++];
					tri.pointA = vtx[indices[index + 0]].Pos;
					tri.pointB = vtx[indices[index + 1]].Pos;
					tri.pointC = vtx[indices[index + 2]].Pos;
				}
			}
			break;
		case video::EVT_2TCOORDS:
			{
				video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buf->getVertices();
				for (u32 index = 0; index < idxCnt; index += 3)
				{
					core::triangle3df & tri = Triangles[triangleCount++];
					tri.pointA = vtx[indices[index + 0]].Pos;
					tri.pointB = vtx[indices[index + 1]].Pos;
					tri.pointC = vtx[indices[index + 2]].Pos;
				}
			}
			break;
		case video::EVT_TANGENTS:
			{
				video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buf->getVertices();
				for (u32 index = 0; index < idxCnt; index += 3)
				{
					core::triangle3df & tri = Triangles[triangleCount++];
					tri.pointA = vtx[indices[index + 0]].Pos;
					tri.pointB = vtx[indices[index + 1]].Pos;
					tri.pointC = vtx[indices[index + 2]].Pos;
				}
			}
			break;
		}
	}
}
Пример #7
0
void TerrainTile::mergeToTile(TerrainTile* tile)
{
    if(!tile || custom)
    {
        #ifdef DEBUG
        cout << "DEBUG : TERRAIN TILE : MERGE FAILED, TILE IS NULL: " << endl;
        #endif
        return;
    }
    else
    {
        IMeshBuffer* meshBuffer = ((IMeshSceneNode*)node)->getMesh()->getMeshBuffer(0);
        IMeshBuffer* neighborBuffer = tile->getMeshBuffer();

        S3DVertex* mb_vertices = (S3DVertex*) meshBuffer->getVertices();
        S3DVertex* n_mb_vertices = (S3DVertex*) neighborBuffer->getVertices();

        u16* mb_indices  = meshBuffer->getIndices();
        u16* n_mb_indices  = neighborBuffer->getIndices();

        for (unsigned int j = 0; j < meshBuffer->getVertexCount(); j += 1)
        {
            for (unsigned int i = 0; i < neighborBuffer->getVertexCount(); i += 1)
            {
                vector3df realPos = mb_vertices[j].Pos*(scale/nodescale) + node->getPosition();
                vector3df nRealPos = n_mb_vertices[i].Pos*(scale/nodescale) + tile->getNode()->getPosition();

                if((realPos.X == nRealPos.X) && (realPos.Z == nRealPos.Z))
                {
                    mb_vertices[j].Pos.Y = n_mb_vertices[i].Pos.Y;
					mb_vertices[j].Normal = n_mb_vertices[i].Normal; //New Copy the normal information
					needrecalc=true;
                }
            }
        }

        //smgr->getMeshManipulator()->recalculateNormals(((IMeshSceneNode*)node)->getMesh(),true);
		((IMeshSceneNode*)node)->getMesh()->setDirty();
		needrecalc = true;

    }
}
Пример #8
0
void TerrainTile::restoreUndo()
{
	if (undohistory.size()>0)
	{
		IMeshBuffer* meshBuffer = ((IMeshSceneNode*)node)->getMesh()->getMeshBuffer(0);

		S3DVertex* mb_vertices = (S3DVertex*)meshBuffer->getVertices();

		u16* mb_indices = meshBuffer->getIndices();
		printf("Here is the undo history size: %i\n", undohistory.size());
		undobuffer = undohistory.back();
		printf("Here is the undo buffer size: %i\n", undobuffer.size());

		for (unsigned int j = 0; j < undohistory[undohistory.size()-1].size(); j += 1)
		{
			mb_vertices[j].Pos.Y = undohistory[undohistory.size() - 1][j];
		}

		meshBuffer = ((IMeshSceneNode*)ocean)->getMesh()->getMeshBuffer(0);

		mb_vertices = (S3DVertex*)meshBuffer->getVertices();

		mb_indices = meshBuffer->getIndices();

		for (unsigned int j = 0; j < undohistory[undohistory.size() - 1].size(); j += 1)
		{
			mb_vertices[j].Pos.Y = undohistory[undohistory.size() - 1][j];
		}
		


		
		needrecalc = true;
		recalculate();
		undohistory.pop_back(); //Remove the last element of the vector by 1;
		
		undobuffer.clear(); //Clear the buffer;
		
	}
	
}
Пример #9
0
bool CSTLMeshWriter::writeMeshASCII(io::IWriteFile* file, scene::IMesh* mesh, s32 flags)
{
	// write STL MESH header

	file->write("solid ",6);
	const core::stringc name(SceneManager->getMeshCache()->getMeshFilename(mesh));
	file->write(name.c_str(),name.size());
	file->write("\n\n",2);

	// write mesh buffers
	
	for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
	{
		IMeshBuffer* buffer = mesh->getMeshBuffer(i);
		if (buffer)
		{
			const u16 indexCount = buffer->getIndexCount();

			switch(buffer->getVertexType())
			{
			case video::EVT_STANDARD:
				{
					video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
					for (u32 j=0; j<indexCount; j+=3)
						writeFace(file,
							vtx[buffer->getIndices()[j]].Pos,
							vtx[buffer->getIndices()[j+1]].Pos,
							vtx[buffer->getIndices()[j+2]].Pos);
				}
				break;
			case video::EVT_2TCOORDS:
				{
					video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
					for (u32 j=0; j<indexCount; j+=3)
						writeFace(file,
							vtx[buffer->getIndices()[j]].Pos,
							vtx[buffer->getIndices()[j+1]].Pos,
							vtx[buffer->getIndices()[j+2]].Pos);
				}
				break;
			case video::EVT_TANGENTS:
				{
					video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
					for (u32 j=0; j<indexCount; j+=3)
						writeFace(file,
							vtx[buffer->getIndices()[j]].Pos,
							vtx[buffer->getIndices()[j+1]].Pos,
							vtx[buffer->getIndices()[j+2]].Pos);
				}
				break;
			}
			file->write("\n",1);
		}
	}

	file->write("endsolid ",9);
	file->write(name.c_str(),name.size());

	return true;
}
Пример #10
0
void TerrainTile::transformMeshToValue(vector3df clickPos, f32 radius, f32 radius2, f32 strength, f32 value, bool norecalc)
{

	if (custom)
		return;

    if(strength<0) strength = -strength;

    IMeshBuffer* meshBuffer = ((IMeshSceneNode*)node)->getMesh()->getMeshBuffer(0);

	S3DVertex* mb_vertices = (S3DVertex*) meshBuffer->getVertices();

	u16* mb_indices  = meshBuffer->getIndices();

	for (unsigned int j = 0; j < meshBuffer->getVertexCount(); j += 1)
	{
	    vector3df realPos = mb_vertices[j].Pos*(scale/nodescale) + node->getPosition();
        clickPos.Y = realPos.Y;
	    if(realPos.getDistanceFrom(clickPos) < radius)
	    {
			needrecalc=true;
            //f32 ratio = sin(radius - realPos.getDistanceFrom(clickPos));
			f32 ratio = radius;

			if (radius2-realPos.getDistanceFrom(clickPos)<0)
				ratio = (radius+radius2)-realPos.getDistanceFrom(clickPos);

            if(mb_vertices[j].Pos.Y > value)
            {
				//mb_vertices[j].Pos.Y -= strength * ratio / (scale/nodescale);
                mb_vertices[j].Pos.Y -= strength * ratio / (scale/nodescale);
                if(mb_vertices[j].Pos.Y <= value) mb_vertices[j].Pos.Y = value;

            }
            if(mb_vertices[j].Pos.Y < value)
            {
		        //mb_vertices[j].Pos.Y += strength * ratio / (scale / nodescale);
				mb_vertices[j].Pos.Y += strength *ratio / (scale / nodescale);
                if(mb_vertices[j].Pos.Y >= value) mb_vertices[j].Pos.Y = value;
            }
	    }
	}

	if (norecalc)
	{
		recalculate(true);
	}
	else
		recalculate();
}
Пример #11
0
void TerrainTile::storeUndo()
{
	IMeshBuffer* meshBuffer = ((IMeshSceneNode*)node)->getMesh()->getMeshBuffer(0);

	S3DVertex* mb_vertices = (S3DVertex*)meshBuffer->getVertices();

	u16* mb_indices = meshBuffer->getIndices();
	
	for (unsigned int j = 0; j < meshBuffer->getVertexCount(); j += 1)
	{
		undobuffer.push_back(mb_vertices[j].Pos.Y);
	}
	undohistory.push_back(undobuffer);
	undobuffer.clear();
}
Пример #12
0
CPlanarShadow::CPlanarShadow(scene::ISceneNode*parent, scene::ISceneManager *mgr, IMesh *mesh, float divisor)
	: ISceneNode(parent, mgr, -1), Vertices(0), Indices(0), SceneManager(mgr), Divisor(divisor), enableDepth(false)
{

	s32 i;
	s32 totalVertices = 0;
	s32 totalIndices = 0;
	s32 bufcnt = mesh->getMeshBufferCount();
	IMeshBuffer* b;

	for (i=0; i<bufcnt; ++i)
	{
		b = mesh->getMeshBuffer(i);
		totalIndices += b->getIndexCount();
		totalVertices += b->getVertexCount();
	}



	Vertices = new core::vector3df[totalVertices];
	Indices = new u16[totalIndices];

	int indStart = 0, vtxNow = 0;

	for (i=0; i < bufcnt; ++i)
	{
		b = mesh->getMeshBuffer(i);

		u16* buff = b->getIndices();

		for (int o = 0; o < b->getIndexCount(); o++)
		{
			Indices[indStart++] = buff[o] + vtxNow;
		}

		vtxNow += b->getVertexCount();

	}

	VertexCount = totalVertices;
	IndexCount = totalIndices;



	buildMesh(mesh);
}
Пример #13
0
void TerrainTile::transformMesh(vector3df clickPos, f32 radius, f32 radius2, f32 strength, bool norecalc)
{

	if (custom)
		return;

    IMeshBuffer* meshBuffer = ((IMeshSceneNode*)node)->getMesh()->getMeshBuffer(0);

	S3DVertex* mb_vertices = (S3DVertex*) meshBuffer->getVertices();

	u16* mb_indices  = meshBuffer->getIndices();

	for (unsigned int j = 0; j < meshBuffer->getVertexCount(); j += 1)
	{
	    vector3df realPos = mb_vertices[j].Pos*(scale/nodescale) + node->getPosition();
        clickPos.Y = realPos.Y;

	    if(realPos.getDistanceFrom(clickPos) < radius)
	    {
			needrecalc=true; // This will flag the tile since it's in the radius and will modify the tile vertices.

            //f32 ratio = sin(radius - realPos.getDistanceFrom(clickPos));
			//- (realPos.getDistanceFrom(clickPos)-radius2)
			f32 ratio = radius;

			if (radius2-realPos.getDistanceFrom(clickPos)<0)
				ratio = (radius+radius2)-realPos.getDistanceFrom(clickPos);

	        mb_vertices[j].Pos.Y += (strength * (ratio)/(scale/nodescale));
			//printf("found something here: vertice %i, vertice Y: %f\n",j, mb_vertices[j].Pos.Y);
	    }

		//if(mb_vertices[j].Pos.Y > nodescale/4) mb_vertices[j].Pos.Y = nodescale/4;
		// Fix up/down limits
		if(mb_vertices[j].Pos.Y > nodescale*0.75f) mb_vertices[j].Pos.Y = nodescale*0.75f;
	    if(mb_vertices[j].Pos.Y < -(nodescale*0.25f)) mb_vertices[j].Pos.Y = -(nodescale*0.25f);
	}

	if (norecalc)
	{
		recalculate(true);
	}
	else
		recalculate();

}
Пример #14
0
void CTriangleSelector::updateFromMesh(const IMesh* mesh) const
{
	if (!mesh)
		return;

	bool skinnnedMesh = mesh->getMeshType() == EAMT_SKINNED;
	u32 meshBuffers = mesh->getMeshBufferCount();
	u32 triangleCount = 0;

	BoundingBox.reset(0.f, 0.f, 0.f);
	for (u32 i = 0; i < meshBuffers; ++i)
	{
		IMeshBuffer* buf = mesh->getMeshBuffer(i);
		u32 idxCnt = buf->getIndexCount();
		const u16* indices = buf->getIndices();

		if ( skinnnedMesh )
		{
			const core::matrix4& bufferTransform = ((scene::SSkinMeshBuffer*)buf)->Transformation;
			for (u32 index = 0; index < idxCnt; index += 3)
			{
				core::triangle3df& tri = Triangles[triangleCount++];
				bufferTransform.transformVect(tri.pointA, buf->getPosition(indices[index + 0]));
				bufferTransform.transformVect(tri.pointB, buf->getPosition(indices[index + 1]));
				bufferTransform.transformVect(tri.pointC, buf->getPosition(indices[index + 2]));
				BoundingBox.addInternalPoint(tri.pointA);
				BoundingBox.addInternalPoint(tri.pointB);
				BoundingBox.addInternalPoint(tri.pointC);
			}
		}
		else
		{
			for (u32 index = 0; index < idxCnt; index += 3)
			{
				core::triangle3df& tri = Triangles[triangleCount++];
				tri.pointA = buf->getPosition(indices[index + 0]);
				tri.pointB = buf->getPosition(indices[index + 1]);
				tri.pointC = buf->getPosition(indices[index + 2]);
				BoundingBox.addInternalPoint(tri.pointA);
				BoundingBox.addInternalPoint(tri.pointB);
				BoundingBox.addInternalPoint(tri.pointC);
			}
		}
	}
}
Пример #15
0
btSoftBody* MeshTools::createSoftBodyFromMesh(btSoftBodyWorldInfo& worldInfo, IMesh* mesh)
{
	IMeshBuffer* buffer = mesh->getMeshBuffer(0);

	vector<btScalar> vertices;
	for (unsigned int i=0; i < buffer->getVertexCount(); ++i)
	{
	    vector3df p = getBaseVertex(buffer, i).Pos;
	    vertices.push_back(p.X);
	    vertices.push_back(p.Y);
	    vertices.push_back(p.Z);
	}

    vector<int> triangles;
    for (unsigned int i=0; i < buffer->getIndexCount(); ++i)
        triangles.push_back(buffer->getIndices()[i]);

    auto result = btSoftBodyHelpers::CreateFromTriMesh(worldInfo, &vertices[0], &triangles[0], buffer->getIndexCount()/3, false);
    result->m_bUpdateRtCst = true;
    return result;
}
Пример #16
0
//! creates the tree
bool COctTreeSceneNode::createTree(IMesh* mesh)
{
	if (!mesh)
		return false;

	MeshName = SceneManager->getMeshCache()->getMeshFilename( mesh );

	deleteTree();

	u32 beginTime = os::Timer::getRealTime();

	u32 nodeCount = 0;
	u32 polyCount = 0;

	Box = mesh->getBoundingBox();

	if (mesh->getMeshBufferCount())
	{
		vertexType = mesh->getMeshBuffer(0)->getVertexType();

		switch(vertexType)
		{
		case video::EVT_STANDARD:
			{
				for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
				{
					IMeshBuffer* b = mesh->getMeshBuffer(i);
					if (b->getVertexCount() && b->getIndexCount()) 
					{
						Materials.push_back(b->getMaterial());

						StdMeshes.push_back(OctTree<video::S3DVertex>::SMeshChunk());
						OctTree<video::S3DVertex>::SMeshChunk &nchunk = StdMeshes.getLast();
						nchunk.MaterialId = Materials.size() - 1;

						u32 v;
						nchunk.Vertices.reallocate(b->getVertexCount());
						for (v=0; v<b->getVertexCount(); ++v)
							nchunk.Vertices.push_back(((video::S3DVertex*)b->getVertices())[v]);

						polyCount += b->getIndexCount();

						nchunk.Indices.reallocate(b->getIndexCount());
						for (v=0; v<b->getIndexCount(); ++v)
							nchunk.Indices.push_back(b->getIndices()[v]);
					}
				}

				StdOctTree = new OctTree<video::S3DVertex>(StdMeshes, MinimalPolysPerNode);
				nodeCount = StdOctTree->getNodeCount();
			}
			break;
		case video::EVT_2TCOORDS:
			{
				for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
				{
					IMeshBuffer* b = mesh->getMeshBuffer(i);

					if (b->getVertexCount() && b->getIndexCount()) 
					{
						Materials.push_back(b->getMaterial());
						LightMapMeshes.push_back(OctTree<video::S3DVertex2TCoords>::SMeshChunk());
						OctTree<video::S3DVertex2TCoords>::SMeshChunk& nchunk = LightMapMeshes.getLast();
						nchunk.MaterialId = Materials.size() - 1;

						u32 v;
						nchunk.Vertices.reallocate(b->getVertexCount());
						for (v=0; v<b->getVertexCount(); ++v)
							nchunk.Vertices.push_back(((video::S3DVertex2TCoords*)b->getVertices())[v]);

						polyCount += b->getIndexCount();
						nchunk.Indices.reallocate(b->getIndexCount());
						for (v=0; v<b->getIndexCount(); ++v)
							nchunk.Indices.push_back(b->getIndices()[v]);
					}
				}

				LightMapOctTree = new OctTree<video::S3DVertex2TCoords>(LightMapMeshes, MinimalPolysPerNode);
				nodeCount = LightMapOctTree->getNodeCount();
			}
			break;
		case video::EVT_TANGENTS:
			{
				for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
				{
					IMeshBuffer* b = mesh->getMeshBuffer(i);

					if (b->getVertexCount() && b->getIndexCount()) 
					{
						Materials.push_back(b->getMaterial());
						TangentsMeshes.push_back(OctTree<video::S3DVertexTangents>::SMeshChunk());
						OctTree<video::S3DVertexTangents>::SMeshChunk& nchunk = TangentsMeshes.getLast();
						nchunk.MaterialId = Materials.size() - 1;

						u32 v;
						nchunk.Vertices.reallocate(b->getVertexCount());
						for (v=0; v<b->getVertexCount(); ++v)
							nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]);

						polyCount += b->getIndexCount();
						nchunk.Indices.reallocate(b->getIndexCount());
						for (v=0; v<b->getIndexCount(); ++v)
							nchunk.Indices.push_back(b->getIndices()[v]);
					}
				}

				TangentsOctTree = new OctTree<video::S3DVertexTangents>(TangentsMeshes, MinimalPolysPerNode);
				nodeCount = TangentsOctTree->getNodeCount();
			}
			break;
		}
	}

	u32 endTime = os::Timer::getRealTime();
	c8 tmp[255];
	sprintf(tmp, "Needed %ums to create OctTree SceneNode.(%u nodes, %u polys)",
		endTime - beginTime, nodeCount, polyCount/3);
	os::Printer::log(tmp, ELL_INFORMATION);

	return true;
}
Пример #17
0
bool CSTLMeshWriter::writeMeshBinary(io::IWriteFile* file, scene::IMesh* mesh, s32 flags)
{
	// write STL MESH header

	file->write("binary ",7);
	const core::stringc name(SceneManager->getMeshCache()->getMeshFilename(mesh));
	const s32 sizeleft = 73-name.size(); // 80 byte header
	if (sizeleft<0)
		file->write(name.c_str(),73);
	else
	{
		char* buf = new char[80];
		memset(buf, 0, 80);
		file->write(name.c_str(),name.size());
		file->write(buf,sizeleft);
		delete [] buf;
	}
	u32 facenum = 0;
	for (u32 j=0; j<mesh->getMeshBufferCount(); ++j)
		facenum += mesh->getMeshBuffer(j)->getIndexCount()/3;
	file->write(&facenum,4);

	// write mesh buffers

	for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
	{
		IMeshBuffer* buffer = mesh->getMeshBuffer(i);
		if (buffer)
		{
			const u16 indexCount = buffer->getIndexCount();

			switch(buffer->getVertexType())
			{
			case video::EVT_STANDARD:
				{
					video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
					const u16 attributes = 0;
					for (u32 j=0; j<indexCount; j+=3)
					{
						file->write(&core::plane3df(vtx[buffer->getIndices()[j]].Pos,vtx[buffer->getIndices()[j+1]].Pos,vtx[buffer->getIndices()[j+2]].Pos).Normal, 12);
						file->write(&vtx[buffer->getIndices()[j]].Pos, 12);
						file->write(&vtx[buffer->getIndices()[j+1]].Pos, 12);
						file->write(&vtx[buffer->getIndices()[j+2]].Pos, 12);
						file->write(&attributes, 2);
					}
				}
				break;
			case video::EVT_2TCOORDS:
				{
					video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
					const u16 attributes = 0;
					for (u32 j=0; j<indexCount; j+=3)
					{
						file->write(&core::plane3df(vtx[buffer->getIndices()[j]].Pos,vtx[buffer->getIndices()[j+1]].Pos,vtx[buffer->getIndices()[j+2]].Pos).Normal, 12);
						file->write(&vtx[buffer->getIndices()[j]].Pos, 12);
						file->write(&vtx[buffer->getIndices()[j+1]].Pos, 12);
						file->write(&vtx[buffer->getIndices()[j+2]].Pos, 12);
						file->write(&attributes, 2);
					}
				}
				break;
			case video::EVT_TANGENTS:
				{
					video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
					const u16 attributes = 0;
					for (u32 j=0; j<indexCount; j+=3)
					{
						file->write(&core::plane3df(vtx[buffer->getIndices()[j]].Pos,vtx[buffer->getIndices()[j+1]].Pos,vtx[buffer->getIndices()[j+2]].Pos).Normal, 12);
						file->write(&vtx[buffer->getIndices()[j]].Pos, 12);
						file->write(&vtx[buffer->getIndices()[j+1]].Pos, 12);
						file->write(&vtx[buffer->getIndices()[j+2]].Pos, 12);
						file->write(&attributes, 2);
					}
				}
				break;
			}
		}
	}
	return true;
}
Пример #18
0
//! writes a mesh
bool COBJMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags)
{
	if (!file)
		return false;

	os::Printer::log("Writing mesh", file->getFileName());

	// write OBJ MESH header

	const core::stringc name(FileSystem->getFileBasename(SceneManager->getMeshCache()->getMeshName(mesh), false)+".mtl");
	file->write("# exported by Irrlicht\n",23);
	file->write("mtllib ",7);
	file->write(name.c_str(),name.size());
	file->write("\n\n",2);

	// write mesh buffers

	core::array<video::SMaterial*> mat;

	u32 allVertexCount=1; // count vertices over the whole file
	for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
	{
		core::stringc num(i+1);
		IMeshBuffer* buffer = mesh->getMeshBuffer(i);
		if (buffer && buffer->getVertexCount())
		{
			file->write("g grp", 5);
			file->write(num.c_str(), num.size());
			file->write("\n",1);

			u32 j;
			const u32 vertexCount = buffer->getVertexCount();
			for (j=0; j<vertexCount; ++j)
			{
				file->write("v ",2);
				getVectorAsStringLine(buffer->getPosition(j), num);
				file->write(num.c_str(), num.size());
			}

			for (j=0; j<vertexCount; ++j)
			{
				file->write("vt ",3);
				getVectorAsStringLine(buffer->getTCoords(j), num);
				file->write(num.c_str(), num.size());
			}

			for (j=0; j<vertexCount; ++j)
			{
				file->write("vn ",3);
				getVectorAsStringLine(buffer->getNormal(j), num);
				file->write(num.c_str(), num.size());
			}

			file->write("usemtl mat",10);
			num = "";
			for (j=0; j<mat.size(); ++j)
			{
				if (*mat[j]==buffer->getMaterial())
				{
					num = core::stringc(j);
					break;
				}
			}
			if (num == "")
			{
				num = core::stringc(mat.size());
				mat.push_back(&buffer->getMaterial());
			}
			file->write(num.c_str(), num.size());
			file->write("\n",1);

			const u32 indexCount = buffer->getIndexCount();
			for (j=0; j<indexCount; j+=3)
			{
				file->write("f ",2);
				num = core::stringc(buffer->getIndices()[j+2]+allVertexCount);
				file->write(num.c_str(), num.size());
				file->write("/",1);
				file->write(num.c_str(), num.size());
				file->write("/",1);
				file->write(num.c_str(), num.size());
				file->write(" ",1);

				num = core::stringc(buffer->getIndices()[j+1]+allVertexCount);
				file->write(num.c_str(), num.size());
				file->write("/",1);
				file->write(num.c_str(), num.size());
				file->write("/",1);
				file->write(num.c_str(), num.size());
				file->write(" ",1);

				num = core::stringc(buffer->getIndices()[j+0]+allVertexCount);
				file->write(num.c_str(), num.size());
				file->write("/",1);
				file->write(num.c_str(), num.size());
				file->write("/",1);
				file->write(num.c_str(), num.size());
				file->write(" ",1);

				file->write("\n",1);
			}
			file->write("\n",1);
			allVertexCount += vertexCount;
		}
	}

	if (mat.size() == 0)
		return true;

	file = FileSystem->createAndWriteFile( name );
	if (file)
	{
		os::Printer::log("Writing material", file->getFileName());

		file->write("# exported by Irrlicht\n\n",24);
		for (u32 i=0; i<mat.size(); ++i)
		{
			core::stringc num(i);
			file->write("newmtl mat",10);
			file->write(num.c_str(),num.size());
			file->write("\n",1);

			getColorAsStringLine(mat[i]->AmbientColor, "Ka", num);
			file->write(num.c_str(),num.size());
			getColorAsStringLine(mat[i]->DiffuseColor, "Kd", num);
			file->write(num.c_str(),num.size());
			getColorAsStringLine(mat[i]->SpecularColor, "Ks", num);
			file->write(num.c_str(),num.size());
			getColorAsStringLine(mat[i]->EmissiveColor, "Ke", num);
			file->write(num.c_str(),num.size());
			num = core::stringc(mat[i]->Shininess/0.128f);
			file->write("Ns ", 3);
			file->write(num.c_str(),num.size());
			file->write("\n", 1);
			if (mat[i]->getTexture(0))
			{
				file->write("map_Kd ", 7);
				file->write(mat[i]->getTexture(0)->getName().getPath().c_str(), mat[i]->getTexture(0)->getName().getPath().size());
				file->write("\n",1);
			}
			file->write("\n",1);
		}
		file->drop();
	}
	return true;
}
Пример #19
0
// ISoftBody::createShape() is taken from code found on the Irrlicht forum
void ISoftBody::createShape(IMesh* const collMesh)
{
    int cMeshBuffer, j;
    IMeshBuffer *mb;
    video::S3DVertex* mb_vertices;
    u16* mb_indices;


    std::map<int, int> index_map;
    std::map<int, int> bullet_map;
    std::map<int, S3DVertex> vertex_map;
    int count = 0;
    indexCount = 0;

    vertexCount = 0;

    for(cMeshBuffer=0; cMeshBuffer < 1; cMeshBuffer++)
    {
        //printf("Loading new mesh buffer for softbody.\n");
        mb = collMesh->getMeshBuffer(cMeshBuffer);
        mb_vertices = (irr::video::S3DVertex*)mb->getVertices();
        mb_indices = mb->getIndices();

        indexCount += mb->getIndexCount();
        vertexCount += mb->getVertexCount();


        for(u32 i=0; i<mb->getIndexCount(); i++)
        {
            int iIndex = mb_indices[i];
            vector3df iVertex = mb_vertices[iIndex].Pos;
            bool isFirst = true;
            for(u32 j=0; j<i; j++)
            {
                int jIndex = mb_indices[j];
                vector3df jVertex = mb_vertices[jIndex].Pos;
                if (iVertex == jVertex)
                {
                    index_map.insert(std::make_pair(i, j));
                    isFirst = false;
                    break;
                }
            }
            // ???????Bullet??Index??????
            if(isFirst)
            {
                // Irrlicht?Index??????Index
                index_map.insert(std::make_pair(i, i));
                // ?????Index????Index
                bullet_map.insert(std::make_pair(i, count));
                // ??Index?????????
                vertex_map.insert(std::make_pair(count, mb_vertices[iIndex]));
                count++;
            }
        }
    }

    indices = new int[indexCount];
    vertexCount = vertex_map.size();
    vertices = new btScalar[vertexCount*3];

    for(j=0; j<indexCount; j++)
    {
        int index1 = index_map.find(j)->second;
        int index2 = bullet_map.find(index1)->second;
        indices[j]   = index2;
    }

    for(j=0; j<vertexCount; j++)
    {
        vertices[3*j] =   vertex_map[j].Pos.X;
        vertices[3*j+1] = vertex_map[j].Pos.Y;
        vertices[3*j+2] = -vertex_map[j].Pos.Z;
    }

    //std::cout << "create softbody" << std::endl;
    object = btSoftBodyHelpers::CreateFromTriMesh(
        dynamicsWorld->getSoftBodyWorldInfo(), vertices,indices, indexCount/3);

    //std::cout << "create map" << std::endl;
    for(int i=0; i<getPointer()->m_faces.size(); i++)
    {
        btSoftBody::Face face = getPointer()->m_faces[i];

        for(int j=0; j<3; j++)
        {
            if(node_map.find(face.m_n[j]) == node_map.end())
            {
                node_map.insert(std::make_pair(face.m_n[j], node_map.size()));
            }
        }

        for(int j=0; j<3; j++)
        {
            m_indices.push_back(node_map.find(face.m_n[j])->second);
        }
    }

    // Reverse node->index to index->node (should be unique on both sides)
    std::map<btSoftBody::Node*, int>::const_iterator node_iter;
    for(node_iter = node_map.begin(); node_iter != node_map.end(); ++node_iter)
    {
        m_vertices.insert(std::make_pair(node_iter->second, node_iter->first));
    }

    //std::cout << "update Irrlicht vertices" << std::endl;
    std::map<int, btSoftBody::Node*>::const_iterator it;


    for(u32 i=0; i<mb->getVertexCount(); i++)
    {
        for(it=m_vertices.begin(); it != m_vertices.end(); ++it)
        {
            int v_index = it->first;
            btSoftBody::Node* node = it->second;
            if(node->m_x.x() == mb_vertices[i].Pos.X &&
                node->m_x.y() == mb_vertices[i].Pos.Y &&
                node->m_x.z() == mb_vertices[i].Pos.Z)
            {
                MeshMap.insert(std::make_pair(i, v_index));
                break;
            }
        }
    }
}
Пример #20
0
	//! draws the element and its children
	void CGUIMeshViewer::draw()
	{
		if (!IsVisible)
			return;

		IGUISkin* skin = Environment->getSkin();
		IVideoDriver* driver = Environment->getVideoDriver();
		rect<SINT32> viewPort = AbsoluteRect;
		viewPort.LowerRightCorner.x -= 1;
		viewPort.LowerRightCorner.y -= 1;
		viewPort.UpperLeftCorner.x += 1;
		viewPort.UpperLeftCorner.y += 1;

		viewPort.clipAgainst(AbsoluteClippingRect);

		// draw the frame

		rect<SINT32> frameRect(AbsoluteRect);
		frameRect.LowerRightCorner.y = frameRect.UpperLeftCorner.y + 1;
		skin->draw2DRectangle(this, skin->getColor(EGDC_3D_SHADOW), frameRect, &AbsoluteClippingRect);

		frameRect.LowerRightCorner.y = AbsoluteRect.LowerRightCorner.y;
		frameRect.LowerRightCorner.x = frameRect.UpperLeftCorner.x + 1;
		skin->draw2DRectangle(this, skin->getColor(EGDC_3D_SHADOW), frameRect, &AbsoluteClippingRect);

		frameRect = AbsoluteRect;
		frameRect.UpperLeftCorner.x = frameRect.LowerRightCorner.x - 1;
		skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), frameRect, &AbsoluteClippingRect);

		frameRect = AbsoluteRect;
		frameRect.UpperLeftCorner.y = AbsoluteRect.LowerRightCorner.y - 1;
		skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), frameRect, &AbsoluteClippingRect);

		// draw the mesh

		if (Mesh)
		{
			//TODO: if outside of screen, dont draw.
			// - why is the absolute clipping rect not already the screen?

			rect<SINT32> oldViewPort = driver->getViewPort();

			driver->setViewPort(viewPort);

			Matrix4 mat;

			//CameraControl->calculateProjectionMatrix(mat);
			//driver->setTransform(TS_PROJECTION, mat);

			mat = Matrix4::IDENTITY;
			mat.setTrans(Vector3(0, 0, 0));
			//mat.setTranslation(Vector3(0, 0, 0));
			driver->setTransform(ETS_WORLD, mat);

			//CameraControl->calculateViewMatrix(mat);
			//driver->setTransform(TS_VIEW, mat);

			driver->setMaterial(Material);

			UINT32 frame = 0;
			if (Mesh->getFrameCount())
				frame = (Timer::getTime() / 20) % Mesh->getFrameCount();
			const IMesh* const m = Mesh->getMesh(frame);
			for (UINT32 i = 0; i<m->getMeshBufferCount(); ++i)
			{
				IMeshBuffer* mb = m->getMeshBuffer(i);
				driver->drawVertexPrimitiveList(mb->getVertices(),
					mb->getVertexCount(), mb->getIndices(),
					mb->getIndexCount() / 3, mb->getVertexType(),
					EPT_TRIANGLES, mb->getIndexType());
			}

			driver->setViewPort(oldViewPort);
		}

		IGUIElement::draw();
	}
Пример #21
0
Vegetation* TerrainTile::paintVegetation(vector3df clickPos, bool erase)
{
	//Do a prior check to see if there is a least one tree active in the list of active objects
	vector<bool> enabled=VegetationSeed::getInstance()->getEnabled();
	vector<int> newlist;
	for(int i = 0; i<(int)enabled.size(); i++)
	{
		if (enabled[i]==true)
			newlist.push_back(i); //New list will contain the list of the enabled items
	}
	if (newlist.size()==0) return NULL;

    IMeshBuffer* meshBuffer = ((IMeshSceneNode*)node)->getMesh()->getMeshBuffer(0);

	S3DVertex* mb_vertices = (S3DVertex*) meshBuffer->getVertices();

	u16* mb_indices  = meshBuffer->getIndices();

	Vegetation* returnvalue = NULL;

	for (unsigned int j = 0; j < meshBuffer->getVertexCount(); j += 1)
	{
	    if(erase)
        {
			vector3df realPos = vector3df (0.0f,0.0f,0.0f);
			//Should be able to place a tree anywhere on a custom model
			if (!custom)
				realPos = mb_vertices[j].Pos*(scale/nodescale) + node->getPosition();
			else
				realPos = clickPos;

            clickPos.Y = realPos.Y;
            if(realPos.getDistanceFrom(clickPos) < vegetationRange/2 && getVegetationAt(vector3df(realPos.X,realPos.Y,realPos.Z)))
            {
                Vegetation* toRemove = getVegetationAt(vector3df(realPos.X,realPos.Y,realPos.Z));
				returnvalue = toRemove;
				return returnvalue;
				// Done outside the function (caller will do the removal)
            }
        }
        else
        {
            vector3df realPos = vector3df (0.0f,0.0f,0.0f);
			//Should be able to place a tree anywhere on a custom model
			if (!custom)
				realPos = mb_vertices[j].Pos*(scale/nodescale) + node->getPosition();
			else
				realPos = clickPos;

            clickPos.Y = realPos.Y; 
            if(realPos.getDistanceFrom(clickPos) < (vegetationRange/2) && !getVegetationAt(vector3df(realPos.X,realPos.Y,realPos.Z)))
            {
                Vegetation* v = new Vegetation();

                //v->setPosition(vector3df(realPos.X + (rand()%5)*0.1f - 0.25f,realPos.Y/(scale/nodescale),realPos.Z + (rand()%5)*0.1f - 0.25f));
				//v->setPosition(vector3df(realPos.X + (rand()%5)*scale/100,realPos.Y,realPos.Z + (rand()%5)*scale/100));
				v->setPosition(vector3df(realPos.X,realPos.Y,realPos.Z));
                f32 treesize = (f32)(rand() % 50 + 25);
				f32 treerot = (f32)(rand() % 1 + 359);

				v->setScale(vector3df(treesize,treesize,treesize));
				v->setRotation(vector3df(0,treerot,0));

#ifdef DEBUG
				printf("Attempting to place a tree with this size: %f\n",treesize);
#endif
                vegetationVector.push_back(v);
				returnvalue = v;

				return returnvalue;

                #ifdef APP_DEBUG
                cout << "DEBUG : TERRAIN TILE : VEGETATION CREATED: " << realPos.X << "," << realPos.Y << "," << realPos.Z << "   TOTAL:" << vegetationVector.size() << endl;
                #endif
	        }
	    }
	}

	return returnvalue;

}
Пример #22
0
MeshTools::SplitMeshResult MeshTools::splitMeshZ(IMesh* oldMesh, float zCut, float zInsert, bool marginalTrisInLeft, bool marginalTrisInRight)
{
    IMeshBuffer* oldMeshBuf = oldMesh->getMeshBuffer(0);
    u16* oldInd = oldMeshBuf->getIndices();
	SMeshBuffer* leftMeshBuf = new SMeshBuffer();
	SMeshBuffer* rightMeshBuf = new SMeshBuffer();
    LinkSplitter linkSplitter(oldMeshBuf, zCut);

    vector3df const offset(0,0, zInsert);

    set<pair<PsblVertPtr, PsblVertPtr>> leftEdgeLinks;
    set<pair<PsblVertPtr, PsblVertPtr>> rightEdgeLinks;

    for (u32 i=0; i < oldMeshBuf->getIndexCount(); i += 3)
    {
        // Calling these shapes instead of triangles because they could be triangle or a quad after slice,
        // (it could also be a degenerate case of a line or a point - those will be discarded by addConvexShape)
        vector<PsblVertPtr> leftShape;
        vector<PsblVertPtr> rightShape;

        int a = oldInd[i];
        int b = oldInd[i+1];
        int c = oldInd[i+2];

        PsblVertPtr mid1;
        PsblVertPtr mid2;
        PsblVertPtr mid3;

        // Don't create a copy just for a triangle that is just kissing the edge.  Leave it in the background.
        if (linkSplitter.compareZ(a)==0 && linkSplitter.compareZ(b)==0 && linkSplitter.compareZ(c)==0)
        {
            if (marginalTrisInLeft)
            {
                leftShape.push_back(linkSplitter.getVert(a));
                leftShape.push_back(linkSplitter.getVert(b));
                leftShape.push_back(linkSplitter.getVert(c));
            }

            if (marginalTrisInRight)
            {
                rightShape.push_back(linkSplitter.getVert(a));
                rightShape.push_back(linkSplitter.getVert(b));
                rightShape.push_back(linkSplitter.getVert(c));
            }
        }
        else
        {
            // This is something I had to think hard about so I'm writing this comment so I don't
            // have to think it through again or forget it:
            //
            // Both the left shape and the right shape, and both the triangle and the quad, "magically"
            // come out with correct winding order when the triangle is split.  Here's why:
            //  Let the original triangle vertices be A-B-C.
            //  Let the split midpoints be AB' and CA' as A-B is split and C-A are split respectively.
            // The shapes (ignore which shape is left or right, call them P and Q instead)
            // will be filled in the following order:
            //
            //  round       P   Q       Comment
            //  1           A   -       A is not in Q at all
            //  1 cont.     AB' AB'     AB' replaces B in P
            //  2           -   B       B proper is in Q and not in P
            //  2 cont.     -   -       Link B-C is not split
            //  3           -   C       C proper is in Q and not in P
            //  3 cont.     CA' CA'     CA' replaces C in P
            //
            // Now, read the columns P and Q vertically top to bottom to see the resultant vertex order.
            // The triangle P is trivially still the correct winding order; it is just a smaller triangle now.
            // The new quad Q retains the old triangle's winding order property for the following reason:
            //  As you wrapped around a full circle in old triangle A-B-C you would have traversed C-A then A-B.
            //      The link C-A has been cut and vertex CA' inserted.
            //      The link A-B has been cut and vertex AB' inserted.
            //  If you traverse the new shape starting from the _middle_ you follow the following path:
            //      B-C     C-CA'   CA'-AB'    AB'-B    B-C (again)
            //  Compare to old triangle:
            //      B-C          C-A        A-B         B-C (again)
            //  Even though vertex A has been cut off and replaced with two vertices, the two
            //  new vertices lie along the path that the old links took and are in the new shape in the right order.

            mid1 = linkSplitter.processLink(leftShape, rightShape, a, b);
            mid2 = linkSplitter.processLink(leftShape, rightShape, b, c);
            mid3 = linkSplitter.processLink(leftShape, rightShape, c, a);
        }

        // If a triangle was split then two of those three midpoints are inhabited by a vertex.
        // We want to get them both in mid1 and mid2 AND we need them in correct order.
        PsblVertPtr cut1 = (mid1 && mid2)? mid1 : mid2;
        PsblVertPtr cut2 = (mid2 && mid3)? mid3 : mid2;

        if (cut1 && cut2)
        {
            vector<PsblVertPtr> chain = linkSplitter.chopLink(cut1, cut2, 1);
            linkSplitter.insertPoints(leftShape, cut1, cut2, chain);
            linkSplitter.insertPoints(rightShape, cut1, cut2, chain);
        }

        linkSplitter.addConvexShape(leftShape, leftMeshBuf,   -offset/2);
        linkSplitter.addConvexShape(rightShape, rightMeshBuf,  offset/2);

        // Add any edges of the left shape that lie along the border.
        linkSplitter.addEdgeLinks(leftShape, leftEdgeLinks);

        // Right side polys that share a border with left side ones will have
        // opposite winding order.  In order for set_intersection to consider them
        // as matches, we'll store the right side links in reversed order.
        std::reverse(rightShape.begin(), rightShape.end());
        linkSplitter.addEdgeLinks(rightShape, rightEdgeLinks);
    }

	SMesh* leftMesh = new SMesh();
	leftMeshBuf->recalculateBoundingBox();
	leftMeshBuf->setHardwareMappingHint(EHM_STATIC);
    leftMesh->addMeshBuffer(leftMeshBuf);
	leftMesh->recalculateBoundingBox();
	leftMeshBuf->drop();  // we drop the buf, mesh obj has it now

	SMesh* rightMesh = new SMesh();
	rightMeshBuf->recalculateBoundingBox();
	rightMeshBuf->setHardwareMappingHint(EHM_STATIC);
    rightMesh->addMeshBuffer(rightMeshBuf);
	rightMesh->recalculateBoundingBox();
	rightMeshBuf->drop();  // we drop the buf, mesh obj has it now

    SMesh* middleMesh = NULL;
    if (zInsert > 0)
    {
        set<pair<PsblVertPtr,PsblVertPtr>> result;
        std::set_intersection(
            leftEdgeLinks.begin(), leftEdgeLinks.end(),
            rightEdgeLinks.begin(), rightEdgeLinks.end(),
            std::inserter(result, result.begin())
        );

        size_t debugsize = result.size();

        if (result.size() > 0)
        {
            SMeshBuffer* middleMeshBuf = new SMeshBuffer();

            vector<PsblVertPtr> shape(4);
            for (auto it=result.begin(); it!=result.end(); ++it)
            {
                shape[0] = it->second;
                shape[1] = it->first;
                shape[2] = it->first->duplicate(offset);
                shape[3] = it->second->duplicate(offset);
                linkSplitter.addConvexShape(shape, middleMeshBuf, -offset/2);
            }

            middleMesh = new SMesh();
            middleMeshBuf->recalculateBoundingBox();
            middleMeshBuf->setHardwareMappingHint(EHM_STATIC);
            middleMesh->addMeshBuffer(middleMeshBuf);
            middleMesh->recalculateBoundingBox();
            middleMeshBuf->drop();  // we drop the buf, mesh obj has it now
        }
    }

	return SplitMeshResult {leftMesh, middleMesh, rightMesh};
}
//! sets the mesh from which the shadow volume should be generated.
void CShadowVolumeSceneNode::setMeshToRenderFrom(IMesh* mesh)
{
    ShadowVolumesUsed = 0;

    s32 oldIndexCount = IndexCount;
    s32 oldVertexCount = VertexCount;

    VertexCount = 0;
    IndexCount = 0;

    if (!mesh)
        return;

    // calculate total amount of vertices and indices

    u32 i;
    s32 totalVertices = 0;
    s32 totalIndices = 0;
    u32 bufcnt = mesh->getMeshBufferCount();
    IMeshBuffer* b;

    for (i=0; i<bufcnt; ++i)
    {
        b = mesh->getMeshBuffer(i);
        totalIndices += b->getIndexCount();
        totalVertices += b->getVertexCount();
    }

    // allocate memory if nececcary

    if (totalVertices > VertexCountAllocated)
    {
        delete [] Vertices;
        Vertices = new core::vector3df[totalVertices];
        VertexCountAllocated = totalVertices;
    }

    if (totalIndices > IndexCountAllocated)
    {
        delete [] Indices;
        Indices = new u16[totalIndices];
        IndexCountAllocated = totalIndices;

        if (UseZFailMethod)
        {
            delete [] FaceData;
            FaceData = new bool[totalIndices / 3];
        }
    }

    // copy mesh

    for (i=0; i<bufcnt; ++i)
    {
        b = mesh->getMeshBuffer(i);

        s32 idxcnt = b->getIndexCount();
        s32 vtxnow = VertexCount;

        const u16* idxp = b->getIndices();
        const u16* idxpend = idxp + idxcnt;

        for (; idxp!=idxpend; ++idxp)
            Indices[IndexCount++] = *idxp + vtxnow;

        s32 vtxcnt = b->getVertexCount();

        switch(b->getVertexType())
        {
        case video::EVT_STANDARD:
        {
            const video::S3DVertex* vp = (video::S3DVertex*)b->getVertices();
            const video::S3DVertex* vpend = vp + vtxcnt;

            for (; vp!=vpend; ++vp)
                Vertices[VertexCount++] = (*vp).Pos;
        }
        break;
        case video::EVT_2TCOORDS:
        {
            const video::S3DVertex2TCoords* vp = (video::S3DVertex2TCoords*)b->getVertices();
            const video::S3DVertex2TCoords* vpend = vp + vtxcnt;

            for (; vp!=vpend; ++vp)
                Vertices[VertexCount++] = (*vp).Pos;
        }
        break;
        case video::EVT_TANGENTS:
        {
            const video::S3DVertexTangents* vp = (video::S3DVertexTangents*)b->getVertices();
            const video::S3DVertexTangents* vpend = vp + vtxcnt;

            for (; vp!=vpend; ++vp)
                Vertices[VertexCount++] = (*vp).Pos;
        }
        break;
        }
    }

    // recalculate adjacency if neccessarry
    if (oldVertexCount != VertexCount &&
            oldIndexCount != IndexCount && UseZFailMethod)
        calculateAdjacency();

    // create as much shadow volumes as there are lights but
    // do not ignore the max light settings.

    u32 lights = SceneManager->getVideoDriver()->getDynamicLightCount();
    core::matrix4 mat = Parent->getAbsoluteTransformation();
    core::vector3df parentpos = Parent->getAbsolutePosition();
    core::vector3df lpos;
    mat.makeInverse();

    for (i=0; i<lights; ++i)
    {
        const video::SLight& dl = SceneManager->getVideoDriver()->getDynamicLight(i);
        lpos = dl.Position;
        if (dl.CastShadows &&
                fabs((lpos - parentpos).getLengthSQ()) <= (dl.Radius*dl.Radius*4.0f))
        {
            mat.transformVect(lpos);
            createShadowVolume(lpos);
        }
    }
}