Beispiel #1
0
	//-----------------------------------------------------------------------------
	MeshPtr ManualObject::convertToMesh(const String& meshName, const String& groupName)
	{
		if (mCurrentSection)
		{
			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
				"You cannot call convertToMesh() whilst you are in the middle of "
				"defining the object; call end() first.",
				"ManualObject::convertToMesh");
		}
		if (mSectionList.empty())
		{
			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
				"No data defined to convert to a mesh.",
				"ManualObject::convertToMesh");
		}
		MeshPtr m = MeshManager::getSingleton().createManual(meshName, groupName);

		for (SectionList::iterator i = mSectionList.begin(); i != mSectionList.end(); ++i)
		{
			ManualObjectSection* sec = *i;
			RenderOperation* rop = sec->getRenderOperation();
			SubMesh* sm = m->createSubMesh();
			sm->useSharedVertices = false;
			sm->operationType = rop->operationType;
			sm->setMaterialName(sec->getMaterialName(), groupName);
			// Copy vertex data; replicate buffers too
			sm->vertexData = rop->vertexData->clone(true);
			// Copy index data; replicate buffers too; delete the default, old one to avoid memory leaks

			// check if index data is present
			if (rop->indexData)
			{
				// Copy index data; replicate buffers too; delete the default, old one to avoid memory leaks
				OGRE_DELETE sm->indexData;
				sm->indexData = rop->indexData->clone(true);
			}
		}
        // update bounds
		m->_setBounds(mAABB);
		m->_setBoundingSphereRadius(mRadius);

		m->load();

		return m;


	}
Beispiel #2
0
void GeomUtils::createCone(const Ogre::String& strName , float radius , float height, int nVerticesInBase)
{
	MeshPtr pCone = MeshManager::getSingleton().createManual(strName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
	SubMesh *pConeVertex = pCone->createSubMesh();
	pCone->sharedVertexData = new VertexData();

	createCone(pCone->sharedVertexData, pConeVertex->indexData
		, radius
		, height
		, nVerticesInBase);

	// Generate face list
	pConeVertex->useSharedVertices = true;

	// the original code was missing this line:
	pCone->_setBounds( AxisAlignedBox( 
		Vector3(-radius, 0, -radius), 
		Vector3(radius, height, radius) ), false );

	pCone->_setBoundingSphereRadius(Math::Sqrt(height*height + radius*radius));
	// this line makes clear the mesh is loaded (avoids memory leaks)
	pCone->load();
}
Beispiel #3
0
	void _prepareMesh()
	{
		int i,lvl ;

		mesh = MeshManager::getSingleton().createManual(name,
            ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME) ;
		subMesh = mesh->createSubMesh();
		subMesh->useSharedVertices=false;

		int numVertices = 4 ;

		if (first) { // first Circle, create some static common data
			first = false ;

			// static buffer for position and normals
			posnormVertexBuffer =
				HardwareBufferManager::getSingleton().createVertexBuffer(
					6*sizeof(float), // size of one vertex data
					4, // number of vertices
					HardwareBuffer::HBU_STATIC_WRITE_ONLY, // usage
					false); // no shadow buffer
			float *posnormBufData = (float*) posnormVertexBuffer->
				lock(HardwareBuffer::HBL_DISCARD);
			for(i=0;i<numVertices;i++) {
				posnormBufData[6*i+0]=((Real)(i%2)-0.5f)*CIRCLE_SIZE; // pos X
				posnormBufData[6*i+1]=0; // pos Y
				posnormBufData[6*i+2]=((Real)(i/2)-0.5f)*CIRCLE_SIZE; // pos Z
				posnormBufData[6*i+3]=0 ; // normal X
				posnormBufData[6*i+4]=1 ; // normal Y
				posnormBufData[6*i+5]=0 ; // normal Z
			}
			posnormVertexBuffer->unlock();

			// static buffers for 16 sets of texture coordinates
			texcoordsVertexBuffers = new HardwareVertexBufferSharedPtr[16];
			for(lvl=0;lvl<16;lvl++) {
				texcoordsVertexBuffers[lvl] =
					HardwareBufferManager::getSingleton().createVertexBuffer(
						2*sizeof(float), // size of one vertex data
						numVertices, // number of vertices
						HardwareBuffer::HBU_STATIC_WRITE_ONLY, // usage
						false); // no shadow buffer
				float *texcoordsBufData = (float*) texcoordsVertexBuffers[lvl]->
					lock(HardwareBuffer::HBL_DISCARD);
				float x0 = (Real)(lvl % 4) * 0.25 ;
				float y0 = (Real)(lvl / 4) * 0.25 ;
				y0 = 0.75-y0 ; // upside down
				for(i=0;i<4;i++) {
					texcoordsBufData[i*2 + 0]=
						x0 + 0.25 * (Real)(i%2) ;
					texcoordsBufData[i*2 + 1]=
						y0 + 0.25 * (Real)(i/2) ;
				}
				texcoordsVertexBuffers[lvl]->unlock();
			}

			// Index buffer for 2 faces
			unsigned short faces[6] = {2,1,0,  2,3,1};
			indexBuffer =
				HardwareBufferManager::getSingleton().createIndexBuffer(
					HardwareIndexBuffer::IT_16BIT,
					6,
					HardwareBuffer::HBU_STATIC_WRITE_ONLY);
			indexBuffer->writeData(0,
				indexBuffer->getSizeInBytes(),
				faces,
				true); // true?
		}

		// Initialize vertex data
		subMesh->vertexData = new VertexData();
		subMesh->vertexData->vertexStart = 0;
		subMesh->vertexData->vertexCount = 4;
		// first, set vertex buffer bindings
		VertexBufferBinding *vbind = subMesh->vertexData->vertexBufferBinding ;
		vbind->setBinding(0, posnormVertexBuffer);
		vbind->setBinding(1, texcoordsVertexBuffers[0]);
		// now, set vertex buffer declaration
		VertexDeclaration *vdecl = subMesh->vertexData->vertexDeclaration ;
		vdecl->addElement(0, 0, VET_FLOAT3, VES_POSITION);
		vdecl->addElement(0, 3*sizeof(float), VET_FLOAT3, VES_NORMAL);
		vdecl->addElement(1, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES);

		// Initialize index data
		subMesh->indexData->indexBuffer = indexBuffer;
		subMesh->indexData->indexStart = 0;
		subMesh->indexData->indexCount = 6;

		// set mesh bounds
		AxisAlignedBox circleBounds(-CIRCLE_SIZE/2.0f, 0, -CIRCLE_SIZE/2.0f,
			CIRCLE_SIZE/2.0f, 0, CIRCLE_SIZE/2.0f);
		mesh->_setBounds(circleBounds);
        mesh->load();
        mesh->touch();
	}
/* *******************************************************************************
 | implement of CGrassSticks
 ******************************************************************************* */
void 
CGrassSticks::createGrassMesh()
{    
	MeshPtr mesh = MeshManager::getSingleton().createManual(GRASS_MESH_NAME, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

	// create a submesh with the grass material
	SubMesh* sm = mesh->createSubMesh();
	sm->setMaterialName("Examples/GrassBlades");
	sm->useSharedVertices = false;
	sm->vertexData = OGRE_NEW VertexData();
	sm->vertexData->vertexStart = 0;
	sm->vertexData->vertexCount = 12;
	sm->indexData->indexCount = 18;

	// specify a vertex format declaration for our mesh: 3 floats for position, 3 floats for normal, 2 floats for UV
	VertexDeclaration* decl = sm->vertexData->vertexDeclaration;
    decl->addElement(0, 0, VET_FLOAT3, VES_POSITION);
    decl->addElement(0, sizeof(float) * 3, VET_FLOAT3, VES_NORMAL);
    decl->addElement(0, sizeof(float) * 6, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);

	// create a vertex buffer
	HardwareVertexBufferSharedPtr vb = HardwareBufferManager::getSingleton().createVertexBuffer
		(decl->getVertexSize(0), sm->vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);

	GrassVertex* verts = (GrassVertex*)vb->lock(HardwareBuffer::HBL_DISCARD);  // start filling in vertex data

	for (unsigned int i = 0; i < 3; i++)  // each grass mesh consists of 3 planes
	{
		// planes intersect along the Y axis with 60 degrees between them
		Real x = Math::Cos(Degree(i * 60)) * GRASS_WIDTH / 2;
		Real z = Math::Sin(Degree(i * 60)) * GRASS_WIDTH / 2;

		for (unsigned int j = 0; j < 4; j++)  // each plane has 4 vertices
		{
			GrassVertex& vert = verts[i * 4 + j];

			vert.x = j < 2 ? -x : x;
			vert.y = j % 2 ? 0 : GRASS_HEIGHT;
			vert.z = j < 2 ? -z : z;

			// all normals point straight up
			vert.nx = 0;
			vert.ny = 1;
			vert.nz = 0;

			vert.u = j < 2 ? 0 : 1;
			vert.v = j % 2;
		}
	}

	vb->unlock();  // commit vertex changes

	sm->vertexData->vertexBufferBinding->setBinding(0, vb);  // bind vertex buffer to our submesh

	// create an index buffer
	sm->indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer
		(HardwareIndexBuffer::IT_16BIT, sm->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);

	// start filling in index data
	Ogre::uint16* indices = (Ogre::uint16*)sm->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD);

	for (unsigned int i = 0; i < 3; i++)  // each grass mesh consists of 3 planes
	{
		unsigned int off = i * 4;  // each plane consists of 2 triangles

		*indices++ = 0 + off;
		*indices++ = 3 + off;
		*indices++ = 1 + off;

		*indices++ = 0 + off;
		*indices++ = 2 + off;
		*indices++ = 3 + off;
	}

	sm->indexData->indexBuffer->unlock();  // commit index changes

    // update mesh AABB
    Ogre::AxisAlignedBox aabb;
    aabb.setExtents(-1,-1,-1,1,1,1);
    mesh->_setBounds(aabb);

    // Ogre::MeshSerializer serial;
    // serial.exportMesh(mesh.getPointer(), "grass.mesh");
}
Beispiel #5
0
Mesh *GrassLoader::generateGrass_SPRITE(PageInfo &page, GrassLayer *layer, float *grassPositions, unsigned int grassCount)
{
	//Calculate the number of quads to be added
	unsigned int quadCount;
	quadCount = grassCount;

	// check for overflows of the uint16's
	unsigned int maxUInt16 = std::numeric_limits<uint16>::max();
	if(grassCount > maxUInt16)
	{
		LogManager::getSingleton().logMessage("grass count overflow: you tried to use more than " + StringConverter::toString(maxUInt16) + " (thats the maximum) grass meshes for one page");
		return 0;
	}
	if(quadCount > maxUInt16)
	{
		LogManager::getSingleton().logMessage("quad count overflow: you tried to use more than " + StringConverter::toString(maxUInt16) + " (thats the maximum) grass meshes for one page");
		return 0;
	}

	//Create manual mesh to store grass quads
	MeshPtr mesh = MeshManager::getSingleton().createManual(getUniqueID(), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
	SubMesh *subMesh = mesh->createSubMesh();
	subMesh->useSharedVertices = false;

	//Setup vertex format information
	subMesh->vertexData = new VertexData;
	subMesh->vertexData->vertexStart = 0;
	subMesh->vertexData->vertexCount = 4 * quadCount;

	VertexDeclaration* dcl = subMesh->vertexData->vertexDeclaration;
	size_t offset = 0;
	dcl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
	offset += VertexElement::getTypeSize(VET_FLOAT3);
	dcl->addElement(0, offset, VET_FLOAT4, VES_NORMAL);
	offset += VertexElement::getTypeSize(VET_FLOAT4);
	dcl->addElement(0, offset, VET_COLOUR, VES_DIFFUSE);
	offset += VertexElement::getTypeSize(VET_COLOUR);
	dcl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES);
	offset += VertexElement::getTypeSize(VET_FLOAT2);

	//Populate a new vertex buffer with grass
	HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton()
		.createVertexBuffer(offset, subMesh->vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
	float* pReal = static_cast<float*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));

	//Calculate size variance
	float rndWidth = layer->maxWidth - layer->minWidth;
	float rndHeight = layer->maxHeight - layer->minHeight;

	float minY = Math::POS_INFINITY, maxY = Math::NEG_INFINITY;
	float *posPtr = grassPositions;	//Position array "iterator"
	for (uint16 i = 0; i < grassCount; ++i)
	{
		//Get the x and z positions from the position array
		float x = *posPtr++;
		float z = *posPtr++;

		//Calculate height
		float y;
		if (heightFunction){
			y = heightFunction(x, z, heightFunctionUserData);
		} else {
			y = 0;
		}

		float x1 = (x - page.centerPoint.x);
		float z1 = (z - page.centerPoint.z);

		//Get the color at the grass position
		uint32 color;
		if (layer->colorMap)
			color = layer->colorMap->getColorAt(x, z, layer->mapBounds);
		else
			color = 0xFFFFFFFF;

		//Calculate size
		float rnd = *posPtr++;	//The same rnd value is used for width and height to maintain aspect ratio
		float halfXScale = (layer->minWidth + rndWidth * rnd) * 0.5f;
		float scaleY = (layer->minHeight + rndHeight * rnd);

		//Randomly mirror grass textures
		float uvLeft, uvRight;
		if (*posPtr++ > 0.5f){
			uvLeft = 0;
			uvRight = 1;
		} else {
			uvLeft = 1;
			uvRight = 0;
		}

		//Add vertices
		*pReal++ = x1; *pReal++ = y; *pReal++ = z1;					//center position
		*pReal++ = -halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0;	//normal (used to store relative corner positions)
		*((uint32*)pReal++) = color;								//color
		*pReal++ = uvLeft; *pReal++ = 0;							//uv

		*pReal++ = x1; *pReal++ = y; *pReal++ = z1;					//center position
		*pReal++ = +halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0;	//normal (used to store relative corner positions)
		*((uint32*)pReal++) = color;								//color
		*pReal++ = uvRight; *pReal++ = 0;							//uv

		*pReal++ = x1; *pReal++ = y; *pReal++ = z1;					//center position
		*pReal++ = -halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0;		//normal (used to store relative corner positions)
		*((uint32*)pReal++) = color;								//color
		*pReal++ = uvLeft; *pReal++ = 1;							//uv

		*pReal++ = x1; *pReal++ = y; *pReal++ = z1;					//center position
		*pReal++ = +halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0;		//normal (used to store relative corner positions)
		*((uint32*)pReal++) = color;								//color
		*pReal++ = uvRight; *pReal++ = 1;							//uv

		//Update bounds
		if (y < minY) minY = y;
		if (y + scaleY > maxY) maxY = y + scaleY;
	}

	vbuf->unlock();
	subMesh->vertexData->vertexBufferBinding->setBinding(0, vbuf);

	//Populate index buffer
	subMesh->indexData->indexStart = 0;
	subMesh->indexData->indexCount = 6 * quadCount;
	subMesh->indexData->indexBuffer = HardwareBufferManager::getSingleton()
		.createIndexBuffer(HardwareIndexBuffer::IT_16BIT, subMesh->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
	uint16* pI = static_cast<uint16*>(subMesh->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
	for (uint16 i = 0; i < quadCount; ++i)
	{
		uint16 offset = i * 4;

		*pI++ = 0 + offset;
		*pI++ = 2 + offset;
		*pI++ = 1 + offset;

		*pI++ = 1 + offset;
		*pI++ = 2 + offset;
		*pI++ = 3 + offset;
	}

	subMesh->indexData->indexBuffer->unlock();
	//subMesh->setBuildEdgesEnabled(autoEdgeBuildEnabled);


	//Finish up mesh
	AxisAlignedBox bounds(page.bounds.left - page.centerPoint.x, minY, page.bounds.top - page.centerPoint.z,
		page.bounds.right - page.centerPoint.x, maxY, page.bounds.bottom - page.centerPoint.z);
	mesh->_setBounds(bounds);
	Vector3 temp = bounds.getMaximum() - bounds.getMinimum();
	mesh->_setBoundingSphereRadius(temp.length() * 0.5f);

	LogManager::getSingleton().setLogDetail(static_cast<LoggingLevel>(0));
	mesh->setAutoBuildEdgeLists(autoEdgeBuildEnabled);
	mesh->load();
	LogManager::getSingleton().setLogDetail(LL_NORMAL);

	//Apply grass material to mesh
	subMesh->setMaterialName(layer->material->getName());

	//Return the mesh
	return mesh.getPointer();
}
Beispiel #6
0
void createSphere(const std::string& strName, const float r, const int nRings = 16, const int nSegments = 16)
{
	MeshPtr pSphere = MeshManager::getSingleton().createManual(strName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
	SubMesh *pSphereVertex = pSphere->createSubMesh();

	pSphere->sharedVertexData = new VertexData();
	VertexData* vertexData = pSphere->sharedVertexData;

	// define the vertex format
	VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
	size_t currOffset = 0;
	// positions
	vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_POSITION);
	currOffset += VertexElement::getTypeSize(VET_FLOAT3);
	// normals
	vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_NORMAL);
	currOffset += VertexElement::getTypeSize(VET_FLOAT3);
	// two dimensional texture coordinates
	vertexDecl->addElement(0, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
	currOffset += VertexElement::getTypeSize(VET_FLOAT2);

	// allocate the vertex buffer
	vertexData->vertexCount = (nRings + 1) * (nSegments + 1);
	HardwareVertexBufferSharedPtr vBuf = HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(0), vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
	VertexBufferBinding* binding = vertexData->vertexBufferBinding;
	binding->setBinding(0, vBuf);
	float* pVertex = static_cast<float*>(vBuf->lock(HardwareBuffer::HBL_DISCARD));

	// allocate index buffer
	pSphereVertex->indexData->indexCount = 6 * nRings * (nSegments + 1);
	pSphereVertex->indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(HardwareIndexBuffer::IT_16BIT, pSphereVertex->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
	HardwareIndexBufferSharedPtr iBuf = pSphereVertex->indexData->indexBuffer;
	unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(HardwareBuffer::HBL_DISCARD));

	float fDeltaRingAngle = (Math::PI / nRings);
	float fDeltaSegAngle = (2 * Math::PI / nSegments);
	unsigned short wVerticeIndex = 0;

	// Generate the group of rings for the sphere
	for (int ring = 0; ring <= nRings; ring++) {
		float r0 = r * sinf(ring * fDeltaRingAngle);
		float y0 = r * cosf(ring * fDeltaRingAngle);

		// Generate the group of segments for the current ring
		for (int seg = 0; seg <= nSegments; seg++) {
			float x0 = r0 * sinf(seg * fDeltaSegAngle);
			float z0 = r0 * cosf(seg * fDeltaSegAngle);

			// Add one vertex to the strip which makes up the sphere
			*pVertex++ = x0;
			*pVertex++ = y0;
			*pVertex++ = z0;

			Vector3 vNormal = Vector3(x0, y0, z0).normalisedCopy();
			*pVertex++ = vNormal.x;
			*pVertex++ = vNormal.y;
			*pVertex++ = vNormal.z;

			*pVertex++ = (float)seg / (float)nSegments;
			*pVertex++ = (float)ring / (float)nRings;

			if (ring != nRings) {
				// each vertex (except the last) has six indices pointing to it
				*pIndices++ = wVerticeIndex + nSegments + 1;
				*pIndices++ = wVerticeIndex;
				*pIndices++ = wVerticeIndex + nSegments;
				*pIndices++ = wVerticeIndex + nSegments + 1;
				*pIndices++ = wVerticeIndex + 1;
				*pIndices++ = wVerticeIndex;
				wVerticeIndex++;
			}
		}; // end for seg
	} // end for ring

	// Unlock
	vBuf->unlock();
	iBuf->unlock();
	// Generate face list
	pSphereVertex->useSharedVertices = true;

	// the original code was missing this line:
	pSphere->_setBounds(AxisAlignedBox(Vector3(-r, -r, -r), Vector3(r, r, r)), false);
	pSphere->_setBoundingSphereRadius(r);
	// this line makes clear the mesh is loaded (avoids memory leaks)
	pSphere->load();
}
	MeshPtr MeshMergeTool::merge(const Ogre::String& name, const Ogre::String& resourceGroupName)
	{
		print("Baking: New Mesh started", V_HIGH);

		MeshPtr mp = MeshManager::getSingleton().createManual(name, resourceGroupName);

		if (!mBaseSkeleton.isNull())
		{
			mp->setSkeletonName(mBaseSkeleton->getName());
		}

		AxisAlignedBox totalBounds = AxisAlignedBox();
		for (std::vector<Ogre::MeshPtr>::iterator it = mMeshes.begin(); it != mMeshes.end(); ++it)
		{
			print("Baking: adding submeshes for " + (*it)->getName(), V_HIGH);

			// insert all submeshes
			for (Ogre::ushort sid = 0; sid < (*it)->getNumSubMeshes(); ++sid)
			{
				SubMesh* sub = (*it)->getSubMesh(sid);
				const String name = findSubmeshName((*it), sid);

				// create submesh with correct name
				SubMesh* newsub;
				if (name.length() == 0)
				{
					newsub = mp->createSubMesh();
				}
				else
				{
					/// @todo check if a submesh with this name has been created before
					newsub = mp->createSubMesh(name);
				}

				newsub->useSharedVertices = sub->useSharedVertices;

				// add index
				newsub->indexData = sub->indexData->clone();

				// add geometry
				if (!newsub->useSharedVertices)
				{
					newsub->vertexData = sub->vertexData->clone();

					if (!mBaseSkeleton.isNull())
					{
						// build bone assignments
						SubMesh::BoneAssignmentIterator bit = sub->getBoneAssignmentIterator();
						while (bit.hasMoreElements())
						{
							VertexBoneAssignment vba = bit.getNext();
							newsub->addBoneAssignment(vba);
						}
					}
				}

				newsub->setMaterialName(sub->getMaterialName());

				// Add vertex animations for this submesh
				Animation *anim = 0;
				for (unsigned short i = 0; i < (*it)->getNumAnimations(); ++i)
				{
					anim = (*it)->getAnimation(i);

					// get or create the animation for the new mesh
					Animation *newanim;
					if (mp->hasAnimation(anim->getName()))
					{
						newanim = mp->getAnimation(anim->getName());
					}
					else
					{
						newanim = mp->createAnimation(anim->getName(), anim->getLength());
					}

					print("Baking: adding vertex animation "
						+ anim->getName() + " for " + (*it)->getName(), V_HIGH);

					Animation::VertexTrackIterator vti=anim->getVertexTrackIterator();
					while (vti.hasMoreElements())
					{
						VertexAnimationTrack *vt = vti.getNext();

						// handle=0 targets the main mesh, handle i (where i>0) targets submesh i-1.
						// In this case there are only submeshes so index 0 will not be used.
						unsigned short handle = mp->getNumSubMeshes();
						VertexAnimationTrack* newvt = newanim->createVertexTrack(
								handle,
								vt->getAssociatedVertexData()->clone(),
								vt->getAnimationType());
						for (int keyFrameIndex = 0; keyFrameIndex < vt->getNumKeyFrames();
							++keyFrameIndex)
						{
							switch (vt->getAnimationType())
							{
								case VAT_MORPH:
								{
									// copy the keyframe vertex buffer
									VertexMorphKeyFrame *kf =
										vt->getVertexMorphKeyFrame(keyFrameIndex);
									VertexMorphKeyFrame *newkf =
										newvt->createVertexMorphKeyFrame(kf->getTime());
									// This creates a ref to the buffer in the original model
									// so don't delete it until the export is completed.
									newkf->setVertexBuffer(kf->getVertexBuffer());
									break;
								}
								case VAT_POSE:
								{
									/// @todo implement pose amination merge
									break;
								}
								case VAT_NONE:
								default:
								{
									break;
								}
							}
						}
					}
				}

				print("Baking: adding submesh '" +
					name + "'  with material " + sub->getMaterialName(), V_HIGH);
			}

			// sharedvertices
			if ((*it)->sharedVertexData)
			{
				/// @todo merge with existing sharedVertexData
				if (!mp->sharedVertexData)
				{
					mp->sharedVertexData = (*it)->sharedVertexData->clone();
				}

				if (!mBaseSkeleton.isNull())
				{
					Mesh::BoneAssignmentIterator bit = (*it)->getBoneAssignmentIterator();
					while (bit.hasMoreElements())
					{
						VertexBoneAssignment vba = bit.getNext();
						mp->addBoneAssignment(vba);
					}
				}
			}

			print("Baking: adding bounds for " + (*it)->getName(), V_HIGH);

			// add bounds
			totalBounds.merge((*it)->getBounds());
		}
		mp->_setBounds(totalBounds);

		/// @todo merge submeshes with same material

		/// @todo add parameters
		mp->buildEdgeList();

		print("Baking: Finished", V_HIGH);

		reset();

		return mp;
	}
Beispiel #8
0
void SplineRoad::RebuildRoadInt(bool editorAlign)
{
	if (!rebuild && !editorAlign)  return;
	rebuild = false;


	//  segments range
	int segs = getNumPoints();
	if (segs == 0 || segs == 1)  return;
	using std::vector;  using std::min;  using std::max;

	UpdRot(); //
	
	if (vSegs.size() != segs || editorAlign)
		iDirtyId = -1;  // force full
		
	int sMin = 0, sMax = segs;
	//  update 4 segs only (fast)
	if (iDirtyId != -1 && segs >= 4)
	{
		// else !isLooped case ...
		sMin =/* max(0,*/ iDirtyId-2;
		sMax =/* min(segs,*/ iDirtyId+2;
	}
	
	//  full rebuild
	QTimer ti;  ti.update();  /// time	
	
	if (iDirtyId == -1)
	{
		DestroyRoad();
		for (int seg=0; seg < segs; ++seg)
		{
			RoadSeg rs;  rs.empty = true;
			vSegs.push_back(rs);
		}
	}


	///  Auto angles prepass ...
	if (segs > 2)
	for (int seg=0; seg < segs; ++seg)
	{
		//int seg1 = (seg+1) % segs;  // next
		int seg0 = (seg-1+segs) % segs;  // prev
				
		if (mP[seg].aType == AT_Manual)
		{	mP[seg].aYaw = mP[seg].mYaw;  mP[seg].aRoll = mP[seg].mRoll;  }
		else
		{	mP[seg].aRoll = 0.f;
			/// ... roll getangle?, +180 loops?, len
			const Real dist = 0.1f;
			Vector3 vl = GetLenDir(seg, 0.f, dist) + GetLenDir(seg0, 1.f-dist, 1.f);  //vl.normalise();
			Vector3 vw = Vector3(vl.z, 0.f, -vl.x);  //vw.normalise();
			mP[seg].aYaw  = GetAngle(vw.x, vw.z) *180.f/PI_d;

			if (mP[seg].aType == AT_Both)
			{	mP[seg].aYaw += mP[seg].mYaw;  mP[seg].aRoll += mP[seg].mRoll;  }	
		}
	}


	///--------------------------------------------------------------------------------------------------------------------------
	///  LOD
	///--------------------------------------------------------------------------------------------------------------------------

	//>  data at lod 0
	vector<int> viLSteps0;
	vector<Real> vSegTc0;
	vector<Vector3> vnSeg0;  // normals

	const int lodDivs[LODs] = {1,2,4,8};

	for (int lod = 0; lod < LODs; ++lod)
	{
		int lodDiv = lodDivs[lod];
		Real lenDiv = lenDiv0 * lodDiv;
		LogR("LOD: "+toStr(lod)+" ---");


		///  segment data pre pass
		//---------------------------------------------------------------------------------------

		//>  data at cur lod
		vector<int> viL, viW;  // vi num steps for seg Length/Width
		vector<int> vbSegMrg;  // bool 0 if seg merged, 1 if new
		vector<Real> vSegTc, vSegLen;
		vector<Vector3> vwSeg;
		vector<vector <int> > viwLS;  //  width steps per length point, for each seg
		vector<int> viwEq;			// 1 if equal width steps at whole length, in seg

		Real sumLenMrg = 0.f, ltc = 0.f;  int mrgGrp = 0;  //#  stats
		Real roadLen = 0.f, rdOnT = 0.f, rdPipe = 0.f,
			avgWidth = 0.f, stMaxH = FLT_MIN, stMinH = FLT_MAX;
				
		
		//if (lod == 0)?
		LogR("--- seg prepass ---");
		for (int seg=0; seg < segs; ++seg)
		{
			int seg1 = (seg+1) % segs;  // next
			int seg0 = (seg-1+segs) % segs;  // prev

			//  width steps  --
			Real sp = mP[seg].pipe, sp1 = mP[seg1].pipe, sp0 = mP[seg0].pipe;
			Real p = sp * iwPmul, pl = max(sp, sp1)* iwPmul/4;
			if (p < 0.f)  p = 1.f;  else  p = 1.f + p;
			if (pl< 0.f)  pl= 1.f;  else  pl= 1.f + pl;

			int iw = max(1, (int)(p * iw0 / lodDiv));  //* wid/widDiv..
			viW.push_back(iw);
			int iwl = max(1, (int)(pl * iw0 / lodDiv));

			//  length steps  |
			Real len = GetSegLen(seg);
			int  il = int(len / lenDiv) / iwl * iwl + iwl;
			Real la = 1.f / il;
			viL.push_back(il);
			vSegLen.push_back(len);
			roadLen += len;  //#
			if (sp > 0.f || sp1 > 0.f)
				rdPipe += len; //#


			///-  Merge conditions
			sumLenMrg += len;
			//  mtr changes
			int hid = mP[seg].idMtr, hid1 = mP[seg1].idMtr, hid0 = mP[seg0].idMtr;
			LogR(toStr(sp0) + "  " + toStr(sp) + "  " + toStr(sp1));

			//  merge road and pipe segs, don't merge transitions
			if (sp != sp1 || sp != sp0  ||  hid != hid1 || hid != hid0)
			{	sumLenMrg = 0.f;  ++mrgGrp;
				vbSegMrg.push_back(1);
			}
			else  //  onTer change
			if (mP[seg].onTer != mP[seg1].onTer || mP[seg].onTer != mP[seg0].onTer)
			{	sumLenMrg = 0.f;  ++mrgGrp;
				vbSegMrg.push_back(1);
			}
			else  if (sumLenMrg >= setMrgLen)
			{	sumLenMrg -= setMrgLen;  ++mrgGrp;
				vbSegMrg.push_back(1);  // bNew
			}else
				vbSegMrg.push_back(0);  // merged
			
			LogR("seg "+toStr(seg)+"  iw "+toStr(iw)+"  il "+toStr(il)+"  pp "+toStr(sp));
			
			if (lod==0)
				viLSteps0.push_back(il);


			///  length <dir>  |
			Vector3 vl = GetLenDir(seg, 0, la), vw;  vl.normalise();
			Real ay = mP[seg].aYaw, ar = mP[seg].aRoll;
			
			///  width <dir>   ---
			if (mP[seg].onTer && mP[seg1].onTer)  //  perpendicular on xz
			{	vw = Vector3(vl.z, 0, -vl.x);  vw.normalise(); 
				//mP[seg].angle = atan2(vl.z, -vl.x)*180.f/PI_d+90.f;  // set yaw..
			}else
				vw = GetRot(ay,ar);  // from angles
				
			///  normal <dir>  /
			if (lod == 0)
			{	Vector3 vn = vl.crossProduct(vw);  vn.normalise();
				//if (vn.y < 0.f)  vn = -vn;  // always up y+
				vnSeg0.push_back(vn);
			}

			Real wiMul = mP[seg].width;
			if (editorAlign)  // wider road for align terrain tool
				wiMul = wiMul*edWmul + edWadd;
			vw *= wiMul;
			vwSeg.push_back(vw);

			avgWidth += mP[seg].width * len;  //#
			if (!mP[seg].onTer || !mP[seg1].onTer)
				rdOnT += len;  //#


			//  tcs  seg il* len
			Real l = 0.f;
			for (int i = 0; i < il; ++i)  // length +1
			{
				//  length dir
				Vector3 vl = GetLenDir(seg, l, l+la);
				l += la;  ltc += vl.length();
			}
			vSegTc.push_back(ltc);
			if (lod == 0)  vSegTc0.push_back(ltc);
		}

		
		LogR("--- seg prepass2  viwLS  ---");
		for (int seg=0; seg < segs; ++seg)
		{
			int seg1 = (seg+1) % segs;  // next
			int il = viL[seg];
			vector<int> viwL;

			//  width steps per lenght point in cur seg
			int iw0 = viW[seg], iw1 = viW[seg1];
			//String ss="";
			for (int i = -1; i <= il+1; ++i)  // length +1  +2-gap
			{
				int ii = max(0, min(il, i));
				int iw = iw0 + (int)( Real(ii)/Real(il) * (iw1-iw0) );
				//if (i==0 || i == il)
				//	ss += toStr(iw)+" ";
				viwL.push_back(iw);
			}
			int eq = iw1==iw0 ? 1 : 0;

			viwEq.push_back(eq);
			viwLS.push_back(viwL);
			//if (!eq)  vbSegMrg[seg] = 1;
			//LogR("seg "+toStr(seg)+"  >> "+ss);
		}

		//#  stats  at lod0, whole road
		bool stats = lod == 0 && iDirtyId == -1;
		if (stats)
		{	st.Length = roadLen;  st.WidthAvg = avgWidth / roadLen;
			st.OnTer = rdOnT / roadLen * 100.f;  st.Pipes = rdPipe / roadLen * 100.f;
			segsMrg = mrgGrp;
		}


		//--------------------------------------------------------------------------------------------------------------------------
		///  segment
		//--------------------------------------------------------------------------------------------------------------------------

		//>  mesh data  W-wall  C-column
		vector<Vector4> clr0/*empty*/, clr;
		vector<Vector3> pos,norm, posW,normW, posC,normC, posLod;
		vector<Vector2> tcs, tcsW, tcsC;
		Real tc1 = 0;  ltc = 0;
		int iLmrg = 0, iLmrgW = 0, iLmrgC = 0;
		Vector3 vlOld;

		int sNum = sMax - sMin, segM = sMin;//, sNumO = sNum;
		while (sNum > 0)
		{
			int seg = (segM + segs) % segs;  // iterator
			int seg1 = (seg+1) % segs;  // next
			
			//if (lod == 0)
			//LogR("[Seg]  cur: " + toStr(seg) + "/" + toStr(sNumO) + "  all:" + toStr(segs));/**/

			//  on terrain  (whole seg)
			bool onTer = mP[seg].onTer && mP[seg1].onTer;
			
			// on merging segs only for game in whole road rebuild
			// off for editor (partial, 4segs rebuild)
			bool bNew = true, bNxt = true;

			if (bMerge)
			{
				bNew = (segM == sMin/*1st*/)	|| vbSegMrg[seg];
				bNxt = (segM+1 == sMax/*last*/) || vbSegMrg[seg1];  // next is new
			}
			
			if (bNew)  //> new seg data
			{	iLmrg = 0;	iLmrgW = 0;  iLmrgC = 0;

				pos.clear();  norm.clear();  tcs.clear();  clr.clear();
				posW.clear(); normW.clear(); tcsW.clear();
				posC.clear(); normC.clear(); tcsC.clear();
			}

			//  bullet create
			bool blt = true;  // game always
			#ifdef ROAD_EDITOR  // editor only sel segs for align ter tool
				blt = editorAlign && vSel.find(seg) != vSel.end();
			#endif
			

			///  destroy old
			RoadSeg& rs = vSegs[seg];
			if (!rs.empty && lod == 0)
				DestroySeg(seg);

			
			const int iwW = 7;  // wall  width steps - types..
			const int iwC = colN;  // column  polygon steps
						
			//  steps len
			int il = viL[seg];        Real la = 1.f / il;
			int il0= viLSteps0[seg];  Real la0= 1.f / il0 * skLen;
			Real l = -la0;

			//  width
			//Real wi1 = abs(mP[seg].width), wi2 = abs(mP[seg1].width), wi12 = wi2-wi1;

			///  angles ()__
			Real ay1 = mP[seg].aYaw, ay2 = mP[seg1].aYaw, ay21 = ay2-ay1;
			Real ar1 = mP[seg].aRoll,ar2 = mP[seg1].aRoll,ar21 = ar2-ar1;
			const Real asw = 180;	// more than 180 swirl - wrong at start/end
			while (ay21 > asw)  ay21 -= 2*asw;  while (ay21 <-asw)  ay21 += 2*asw;
			while (ar21 > asw)  ar21 -= 2*asw;	while (ar21 <-asw)  ar21 += 2*asw;

			//  tc begin,range
			Real tcBeg = (seg > 0) ? vSegTc[seg-1] : 0.f,  tcEnd  = vSegTc[seg],  tcRng  = tcEnd - tcBeg;
			Real tcBeg0= (seg > 0) ? vSegTc0[seg-1]: 0.f,  tcEnd0 = vSegTc0[seg], tcRng0 = tcEnd0 - tcBeg0;
			Real tcRmul = tcRng0 / tcRng;


			//------------------------------------------------------------------------------------
			//  Length  vertices
			//------------------------------------------------------------------------------------
			//LogR( " __len");
			if (mP[seg].idMtr >= 0)  // -1 hides segment
			for (int i = -1; i <= il+1; ++i)  // length +1  +2-gap
			{
				++iLmrg;
				///  length <dir>  |
				Vector3 vL0 = interpolate(seg, l);
				Vector3 vl = GetLenDir(seg, l, l+la), vw;
				Real len = vl.length();  vl.normalise();
				
				//  len tc
				if (i <= 0)  ltc = 0;
				Real tc = ltc * tcRmul + tcBeg0;
				//  skirt tc
				if (i == -1)	tc =-skLen* tcRmul + tcBeg0;
				if (i == il+1)  tc = skLen* tcRmul + tcEnd0;
				
				///  width <dir>   --
				if (mP[seg].onTer && mP[seg1].onTer)
				{	vw = Vector3(vl.z, 0, -vl.x);  }
				else		/// angles ()__
				{	Real ay = ay1 + ay21 * l;  // linear-
					Real ar = ar1 + ar21 * l;
					//Real ay = interpAYaw(seg,l);  // spline~
					//Real ar = interpARoll(seg,l);  // err swirl..
					vw = GetRot(ay,ar);  // from angles
				}
				vw.normalise();
				Vector3 vwn = vw;

				//Real wiMul = wi1 + wi12 * l;  // linear-
				Real wiMul = interpWidth(seg, l);  // spline~
				if (editorAlign)  // wider road for align terrain tool
					wiMul = wiMul*edWmul + edWadd;
				vw *= wiMul;

				//  last vw = 1st form next seg		
				if (i==il && seg < segs-1)
					vw = vwSeg[seg+1];
				
				//  on terrain ~~
				bool onTer1 = onTer || mP[seg].onTer && i==0 || mP[seg1].onTer && i==il;

				///  normal <dir>  /
				Vector3 vn = vl.crossProduct(vw);  vn.normalise();
				if (i==0)	vn = vnSeg0[seg];  // seg start=end
				if (i==il)	vn = vnSeg0[seg1];
				//Vector3 vnu = vn;  if (vnu.y < 0)  vnu = -vnu;  // always up y+


				//  width steps <->
				//int iw = viW[seg];
				int iw = viwLS[seg][i+1];  //i = -1 .. il+1

				//  pipe width
				Real l01 = max(0.f, min(1.f, Real(i)/Real(il) ));
				Real p1 = mP[seg].pipe, p2 = mP[seg1].pipe;
				Real pipe = p1 + (p2-p1)*l01;
				bool trans = (p1 == 0.f || p2 == 0.f) && !viwEq[seg];
				Real trp = (p1 == 0.f) ? 1.f - l01 : l01;
				//LogR("   il="+toStr(i)+"/"+toStr(il)+"   iw="+toStr(iw)
				//	/*+(bNew?"  New ":"") +(bNxt?"  Nxt ":"")/**/);
				
				///  road ~    Width  vertices
				//-----------------------------------------------------------------------------------------------------------------
				for (int w=0; w <= iw; ++w)  // width +1
				{
					//  pos create
					Vector3 vP,vN;	Real tcw = Real(w)/Real(iw);

					Real yTer = 0.f;
					if (pipe == 0.f)
					{	//  flat --
						vP = vL0 + vw * (tcw - 0.5);
						vN = vn;
						yTer = mTerrain ? mTerrain->getHeightAtWorldPosition(vP.x, 0, vP.z) : 0.f;
						if (onTer1)  //  onTerrain
						{
							vP.y = yTer + fHeight * ((w==0 || w==iw) ? 0.15f : 1.f);
							vN = mTerrain ? getNormalAtWorldPosition(mTerrain, vP.x, vP.z, lenDiv*0.5f /*0.5f*/) : Vector3::UNIT_Y;
						}
					}else
					{	///  pipe (_)
						Real oo = (tcw - 0.5)/0.5 * PI_d * pipe, so = sinf(oo), co = cosf(oo);
						vP = vL0 + vw  * 0.5 * so +
								 + vn * (0.5 - 0.5 * co) * wiMul;
						vN = vn * co + vwn * so;

						if (vN.y < 0.f)  vN.y = -vN.y;
						if (trans)  //  transition from flat to pipe
						{	vP += vw * (tcw - 0.5) * trp;  }
						yTer = mTerrain ? mTerrain->getHeightAtWorldPosition(vP.x, 0, vP.z) : 0.f;
					}
					
					//  skirt, gap patch_
					if (i == -1 || i == il+1)
						vP -= vn * skH;


					//  color - for minimap preview
					//  ---~~~====~~~---
					Real brdg = min(1.f, abs(vP.y - yTer) * 0.4f);  //par ] height diff mul
					Real h = max(0.f, 1.f - abs(vP.y - yTer) / 30.f);  // for grass dens tex
					Real blend = 0.f;  //rand()%1000/1000.f; // TODO: blend 2materials...?
					Vector4 c(brdg,pipe, blend, h);

					//>  data road
					pos.push_back(vP);	norm.push_back(vN);
					tcs.push_back(Vector2(tcw * 1.f /**2p..*/, tc * tcMul));
					clr.push_back(c);
					//#
					if (vP.y < stMinH)  stMinH = vP.y;
					if (vP.y > stMaxH)  stMaxH = vP.y;
				}
				

				///  wall ]
				//------------------------------------------------------------------------------------
				struct stWiPntW {  Real x,y, uv, nx,ny;  };  // wall width points
				const static stWiPntW wiPntW[iwW+1][2] = {  // section shape
					//  normal road                     //  pipe wall
					{{-0.5f, -0.1f, 0.0f,  1.0f, 0.0f}, {-0.28f, 0.7f, 0.0f, -1.0f, 0.0f}},
					{{-0.5f,  1.2f, 0.5f,  0.5f, 0.5f}, {-0.28f, 0.5f, 0.2f, -0.5f, 0.5f}},
					{{-0.56f, 1.2f, 0.2f, -0.5f, 0.5f}, {-0.28f, 0.0f, 0.2f, -0.5f, 0.0f}},
					{{-0.56f,-0.9f, 1.6f, -0.5f,-0.5f}, {-0.2f, -0.9f, 0.5f, -0.1f,-0.5f}},
					{{ 0.56f,-0.9f, 3.0f,  0.5f,-0.5f}, { 0.2f, -0.9f, 0.5f,  0.1f,-0.5f}},
					{{ 0.56f, 1.2f, 1.6f,  0.5f, 0.5f}, { 0.28f, 0.0f, 0.2f,  0.5f, 0.0f}},
					{{ 0.5f,  1.2f, 0.2f, -0.5f, 0.5f}, { 0.28f, 0.5f, 0.2f,  0.5f, 0.5f}},
					{{ 0.5f, -0.1f, 0.5f, -1.0f, 0.0f}, { 0.28f, 0.7f, 0.2f,  1.0f, 0.0f}}};
				Real uv = 0.f;  // tc long

				if (!onTer)
				if (i >= 0 && i <= il)  // length +1
				{	++iLmrgW;

					for (int w=0; w <= iwW; ++w)  // width +1
					{
						int pp = (p1 > 0.f || p2 > 0.f) ? 1 : 0;  //  pipe wall
						stWiPntW wP = wiPntW[w][pp];

						if (trans /*&& (w <= 3 || w >= iwW-3)*/)
						{	wP.x *= 1 + trp;  wP.y *= 1 - trp;  }
						uv += wP.uv;

						Vector3 vP = vL0 + vw * wP.x + vn * wP.y;
						Vector3 vN =     vwn * wP.nx + vn * wP.ny;  vN.normalise();

						//>  data Wall
						posW.push_back(vP);  normW.push_back(vN);
						tcsW.push_back(0.25f * Vector2(uv, tc * tcMul));  //pars
					}
				}
				
				
				///  columns |
				//------------------------------------------------------------------------------------
				if (!onTer && mP[seg].cols > 0)
				if (i == il/2)  // middle-
				{	++iLmrgC;
					const Real r = colR;  // column radius

					for (int h=0; h <= 1; ++h)  // height
					for (int w=0; w <= iwC; ++w)  // width +1
					{
						Real ht = (h==0) ? 0.f : vL0.y - (mTerrain ? mTerrain->getHeightAtWorldPosition(vL0) : 0.f);
						Real a = Real(w)/iwC *2*PI_d,  //+PI_d/4.f
							x = r*cosf(a), y = r*sinf(a);

						Vector3 vlXZ(vl.x,0,vl.z);	Real fl = 1.f/max(0.01f, vlXZ.length());
						Vector3 vP = vL0 + fl * vl * x + vwn * y;
						Real yy;

						if (h==0)  // top below road
						{	yy = vn.y * -0.8f;  //pars
							vP.y += yy;  ht += yy;
						}
						else  // bottom below ground
						{	yy = (mTerrain ? mTerrain->getHeightAtWorldPosition(vP) : 0.f) - 0.3f;
							vP.y = yy;
						}
						ht += yy;

						Vector3 vN(vP.x-vL0.x,0,vP.z-vL0.z);  vN.normalise();

						//>  data Col
						posC.push_back(vP);  normC.push_back(vN);
						tcsC.push_back(Vector2( Real(w)/iwC * 4, ht * 0.2f ));  //pars
					}
				}
				
				
				if (i == -1 || i == il)  // add len
				{	l += la0;  ltc += len;  }
				else
				{	l += la;  ltc += len;  }
			}
			//  Length  vertices
			//------------------------------------------------------------------------------------
			

			//  lod vis points
			if (lod == 0)
			{	int lps = max(2, (int)(vSegLen[seg] / lposLen));

				for (int p=0; p <= lps; ++p)
				{
					Vector3 vp = interpolate(seg, Real(p)/Real(lps));
					posLod.push_back(vp);
				}
			}


			//---------------------------------------------------------------------------------------------------------
			///  create mesh  indices
			//---------------------------------------------------------------------------------------------------------
			if (bNxt && !pos.empty())  /*Merging*/
			{
				String sEnd = toStr(idStr);  ++idStr;
				String sMesh = "rd.mesh." + sEnd, sMeshW = sMesh + "W", sMeshC = sMesh + "C";

				posBt.clear();
				idx.clear();  // set for addTri
				at_pos = &pos;  at_size = pos.size();  at_ilBt = iLmrg-2;
				
				///  road ~
				int iiw = 0;  //LogR( " __idx");

				//  equal width steps
				if (viwEq[seg]==1)
					for (int i = 0; i < iLmrg-1; ++i)  // length-1 +2gap
					{
						int iw = viW[seg];  // grid  w-1 x l-1 x2 tris
						for (int w=0; w < iw; ++w)  // width-1
						{
							//LogR( "   il="+toStr(i)+"/"+toStr(il)+"   iw="+toStr(iw));
							int f0 = iiw + w, f1 = f0 + (iw+1);
							addTri(f0+0,f1+1,f0+1,i, blt);
							addTri(f0+0,f1+0,f1+1,i, blt);
						}
						iiw += iw+1;
					}
				else
					//  pipe, diff width_
					for (int i = 0; i < iLmrg-1; ++i)  // length-1 +2gap
					{
						int iw = viwLS[seg][i], iw1 = viwLS[seg][i+1];
						int sw = iw1 < iw ? 1 : 0;
						//LogR( "   il="+toStr(i)+"/"+toStr(il)+"   iw="+toStr(iw));
						
						//int w=0;  // test fans
						for (int w=0; w < iw -sw; ++w)  // width-1
						{
							int f0 = iiw + w, f1 = f0 + (iw+1);
							//  |\ |  f0+0  f0+1
							//  | \|  f1+0  f1+1
							if (sw==0) {
								addTri(f0+0,f1+1,f0+1,i, blt);
								addTri(f0+0,f1+0,f1+1,i, blt);  }
							else {  // |/|
								addTri(f0+0,f1+0,f0+1,i, blt);
								addTri(f0+1,f1+0,f1+1,i, blt);  }
						}

						///>>>  fix gaps when iw changes - fan tris
						int ma = iw1 - iw, ms = -ma, m;
						for (m=0; m < ma; ++m)
						{
							int f0 = iiw + iw-1, f1 = f0 + (iw+2)+m;
							addTri(f0+1,f1+0,f1+1,i, blt);
						}
						for (m=0; m < ms; ++m)
						{
							int f0 = iiw + iw-sw -m, f1 = f0 + (iw+1);
							addTri(f0+0,f1+0,f0+1,i, blt);
						}
						iiw += iw + 1;
					}
				vSegs[seg].nTri[lod] = idx.size()/3;


				//  create Ogre Mesh
				//-----------------------------------------
				MeshPtr meshOld = MeshManager::getSingleton().getByName(sMesh);
				if (!meshOld.isNull())  LogR("Mesh exists !!!" + sMesh);

				AxisAlignedBox aabox;
				MeshPtr mesh = MeshManager::getSingleton().createManual(sMesh,"General");
				SubMesh* sm = mesh->createSubMesh();
				
				int id = max(0,mP[seg].idMtr);
				if (isPipe(seg))
					rs.sMtrRd = sMtrPipe[id];
				else
					rs.sMtrRd = sMtrRoad[id] + (onTer ? "_ter" :"");

				CreateMesh(sm, aabox, pos,norm,clr,tcs, idx, rs.sMtrRd);

				MeshPtr meshW, meshC;  // ] |
				bool wall = !posW.empty();
				if (wall)
				{
					meshW = MeshManager::getSingleton().createManual(sMeshW,"General");
					meshW->createSubMesh();
				}
				bool cols = !posC.empty() && lod == 0;  // cols have no lods
				if (cols)
				{
					meshC = MeshManager::getSingleton().createManual(sMeshC,"General");
					meshC->createSubMesh();
				}
				//*=*/wall = 0;  cols = 0;  // test


				///  wall ]
				//------------------------------------------------------------------------------------
				// wall pipe glass mtr
				bool wPglass = isPipe(seg) && mP[seg].idMtr >= 1;  // wall pipe glass mtr
				//bool wPglass = isPipe(seg) && StringUtil::match(sMtrPipe[mP[seg].idMtr], "*lass*");
				if (wall)
				{
					idx.clear();
					for (int i = 0; i < iLmrgW-1; ++i)  // length
					{	int iiW = (i+0)*(iwW+1);

						for (int w=0; w < iwW; ++w)  // width
						{
							int f0 = iiW + w, f1 = f0 + (iwW+1);
							idx.push_back(f0+1);  idx.push_back(f1+1);  idx.push_back(f0+0);
							idx.push_back(f1+1);  idx.push_back(f1+0);  idx.push_back(f0+0);
						}
					}
					
					//  front plates start,end
					const int Wid[4/*6*/][3] = {{2,1,0},{3,2,0},{5,4,7},{6,5,7}/*,{7,3,0},{4,3,7}*/};
					int i,f, b = posW.size()-iwW-1;

					if (!isPipe(seg))  //  no fronts in pipes
					for (f=0; f < 4; ++f)
					{
						for (i=0; i<=2; ++i)  idx.push_back( Wid[f][i] );
						for (i=0; i<=2; ++i)  idx.push_back( Wid[f][2-i]+b );
					}
					vSegs[seg].nTri[lod] += idx.size()/3;

					sm = meshW->getSubMesh(0);   // for glass only..
					rs.sMtrWall = !wPglass ? sMtrWall : sMtrWallPipe;
					if (!posW.empty())
						CreateMesh(sm, aabox, posW,normW,clr0,tcsW, idx, rs.sMtrWall);
				}
				
				
				///  columns |
				//------------------------------------------------------------------------------------
				if (cols)
				{
					idx.clear();
					at_pos = &posC;

					for (int l=0; l < iLmrgC; ++l)
					for (int w=0; w < iwC; ++w)
					{
						int f0 = w + l*(iwC+1)*2, f1 = f0 + iwC+1;
						addTri(f0+0, f1+1, f0+1, 1, blt);
						addTri(f0+0, f1+0, f1+1, 1, blt);
					}					
					vSegs[seg].nTri[lod] += idx.size()/3;

					sm = meshC->getSubMesh(0);
					//if (!posC.empty())
					CreateMesh(sm, aabox, posC,normC,clr0,tcsC, idx, sMtrCol);
				}
				
								
				//  add Mesh to Scene  -----------------------------------------
				Entity* ent = 0, *entW = 0, *entC = 0;
				SceneNode* node = 0, *nodeW = 0, *nodeC = 0;

				AddMesh(mesh, sMesh, aabox, &ent, &node, "."+sEnd);
				if (wPglass)
				{
					ent->setRenderQueueGroup(RQG_PipeGlass);
					//ent->setCastShadows(true);
				}
				if (wall /*&& !posW.empty()*/)
				{
					AddMesh(meshW, sMeshW, aabox, &entW, &nodeW, "W."+sEnd);
					entW->setCastShadows(true);  // only cast
				}
				if (cols /*&& !posC.empty()*/)
				{
					AddMesh(meshC, sMeshC, aabox, &entC, &nodeC, "C."+sEnd);
					entC->setVisible(true);  
					if (bCastShadow)
						entC->setCastShadows(true);
				}
				if (bCastShadow && !onTer)
					ent->setCastShadows(true);

				
				//>>  store ogre data  ------------
				rs.road[lod].node = node;	rs.wall[lod].node = nodeW;
				rs.road[lod].ent = ent;		rs.wall[lod].ent = entW;
				rs.road[lod].mesh = mesh;	rs.wall[lod].mesh = meshW;
				rs.road[lod].smesh = sMesh; rs.wall[lod].smesh = sMeshW;
				if (lod==0)  {
					rs.col.node = nodeC;
					rs.col.ent = entC;
					rs.col.mesh = meshC;
					rs.col.smesh = sMeshC;  }
				rs.empty = false;  // new

				//  copy lod points
				if (lod == 0)
				{	for (size_t p=0; p < posLod.size(); ++p)
						rs.lpos.push_back(posLod[p]);
					posLod.clear();
				}
				//#  stats--
				if (stats)
				{
					rs.mrgLod = (iMrgSegs % 2)*2+1;  //-
					iMrgSegs++;	 // count, full
				}


				///  bullet trimesh  at lod 0
				///------------------------------------------------------------------------------------
				if (lod == 0 && blt)
				{
					btTriangleMesh* trimesh = new btTriangleMesh();  vbtTriMesh.push_back(trimesh);
					#define vToBlt(v)  btVector3(v.x, -v.z, v.y)
					#define addTriB(a,b,c)  trimesh->addTriangle(vToBlt(a), vToBlt(b), vToBlt(c), blt);

					size_t si = posBt.size(), a=0;  // %3!
					for (size_t i=0; i < si/3; ++i,a+=3)
						addTriB(posBt[a], posBt[a+1], posBt[a+2]);

					// if (cols)  // add columns^..
					
					//  Road  ~
					btCollisionShape* shape = new btBvhTriangleMeshShape(trimesh, true);
					shape->setUserPointer(isPipe(seg) ? (void*)7788 : (void*)7777);  // mark as road,  + mtrId..
					
					//btRigidBody::btRigidBodyConstructionInfo infoT(0.f, 0, shape);
					//infoT.m_restitution = 0.0f;
					//infoT.m_friction = 0.8f;  // 1 like terrain
					//pGame->collision.AddRigidBody(infoT);  // old

					btCollisionObject* bco = new btCollisionObject();
					btTransform tr;  tr.setIdentity();  //tr.setOrigin(pc);
					bco->setActivationState(DISABLE_SIMULATION);
					bco->setCollisionShape(shape);	bco->setWorldTransform(tr);
					bco->setFriction(0.8f);  bco->setRestitution(0.f);  //`
					bco->setCollisionFlags(bco->getCollisionFlags() |
						btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT/**/);
					#ifdef ROAD_EDITOR
						pApp->world->addCollisionObject(bco);
					#else
						pGame->collision.world->addCollisionObject(bco);
						pGame->collision.shapes.push_back(shape);
					#endif
					
					//  Wall  ]
					#ifndef ROAD_EDITOR  // in Game
					if (wall)
					{	trimesh = new btTriangleMesh();  vbtTriMesh.push_back(trimesh);
						
						for (int i = 0; i < iLmrgW-1; ++i)  // length
						{	int iiW = i* (iwW+1);

							for (int w=0; w < iwW; ++w)  // width
							if (bRoadWFullCol || w==0 || w == iwW-1)  // only 2 sides|_| optym+
							{
								int f = iiW + w, f1 = f + (iwW+1);
								addTriB(posW[f+0], posW[f1+1], posW[f+1]);
								addTriB(posW[f+0], posW[f1+0], posW[f1+1]);
							}
						}
						
						btCollisionShape* shape = new btBvhTriangleMeshShape(trimesh, true);
						shape->setUserPointer((void*)7777);  //-  + road mtr id todo...
						
						btCollisionObject* bco = new btCollisionObject();
						bco->setActivationState(DISABLE_SIMULATION);
						bco->setCollisionShape(shape);	bco->setWorldTransform(tr);
						bco->setFriction(0.1f);  bco->setRestitution(0.f);  //`
						bco->setCollisionFlags(bco->getCollisionFlags() |
							btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT/**/);
						pGame->collision.world->addCollisionObject(bco);
						pGame->collision.shapes.push_back(shape);
					}
					#endif
				}

			}/*bNxt Merging*/

			sNum--;  segM++;  // next
		}
		///  segment end
		//--------------------------------------------------------------------------------------------------------------------------
	
		//#  stats
		if (stats)
			st.HeightDiff = max(0.f, stMaxH - stMinH);
	}
	//  lod end

	
	UpdLodVis(fLodBias);
	if (iDirtyId == -1)
		iOldHide = -1;


	if (iDirtyId == -1)
	//if (segs <= 4 || sMax - sMin > 4)
	{
		ti.update();	/// time
		float dt = ti.dt * 1000.f;
		LogO(String("::: Time Road Rebuild: ") + toStr(dt) + " ms");
	}
}
    MeshPtr MergeMesh::bake()
    {    
        log( 
             "Baking: New Mesh started" );

        MeshPtr mp = MeshManager::getSingleton().
            createManual( "mergedMesh", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );
        mp->setSkeletonName( m_BaseSkeleton->getName() );

        AxisAlignedBox totalBounds = AxisAlignedBox();
        for( std::vector< Ogre::MeshPtr >::iterator it = m_Meshes.begin();
             it != m_Meshes.end(); ++it )
        {   
            log( 
                "Baking: adding submeshes for " + (*it)->getName() );

            // insert all submeshes
            for( Ogre::ushort sid = 0; sid < (*it)->getNumSubMeshes(); ++sid )
            {
                SubMesh* sub = (*it)->getSubMesh( sid );
                const String name = findSubmeshName( (*it), sid );                
                
                // create submesh with correct name                
                SubMesh* newsub;
                if( name.length() == 0 )
                    newsub = mp->createSubMesh(  );
                else 
                /// @todo check if a submesh with this name has been created before
                    newsub = mp->createSubMesh( name );   

                newsub->useSharedVertices = sub->useSharedVertices;

                // add index
                newsub->indexData = sub->indexData->clone();

                // add geometry
                if( !newsub->useSharedVertices )
                {
                    newsub->vertexData = sub->vertexData->clone();
                
                    // build bone assignments
                    SubMesh::BoneAssignmentIterator bit = sub->getBoneAssignmentIterator();
                    while (bit.hasMoreElements())
                    {
                        VertexBoneAssignment vba = bit.getNext();
                        newsub->addBoneAssignment(vba);
                    }
                }

                newsub->setMaterialName( sub->getMaterialName() );

                log("Baking: adding submesh '" + name + "'  with material " + sub->getMaterialName());
            } 

            // sharedvertices
            if ((*it)->sharedVertexData)
            {
                /// @todo merge with existing sharedVertexData
                if (!mp->sharedVertexData)
				{
					mp->sharedVertexData = (*it)->sharedVertexData->clone();
				}

                Mesh::BoneAssignmentIterator bit = (*it)->getBoneAssignmentIterator();
                while (bit.hasMoreElements())
                {
                    VertexBoneAssignment vba = bit.getNext();
                    mp->addBoneAssignment(vba);
                }
            }

            log("Baking: adding bounds for " + (*it)->getName());

            // add bounds
            totalBounds.merge((*it)->getBounds());
        }           
        mp->_setBounds( totalBounds );

        /// @todo merge submeshes with same material


        /// @todo add parameters
        mp->buildEdgeList();

        log( 
            "Baking: Finished" );

        return mp;
	}
Beispiel #10
0
void Tile::_generateSubMesh(MeshPtr& mesh)
{
	// Create a submesh to the given mesh.
	SubMesh* tileMesh = mesh->createSubMesh();

	// Define the vertices.
	size_t index = 0;
	size_t vertCount = this->mCorners.size() + 1; // corner count + center corner

	Real* vertices = new Real[vertCount*3*2];    // (number of verts)*(x, y, z)*(coord, normal) -or- vertCount*3*2

	// Manually add center vertex.
	// -- Position (ord: x, y, z)
	vertices[index++] = this->mPosition.x;
	vertices[index++] = (Ogre::Real)(this->elevation);
	vertices[index++] = this->mPosition.y;

	// -- Normal (ord: x, y, z)
	Vector3 norm = Vector3::UNIT_Y;

	vertices[index++] = norm.x;
	vertices[index++] = norm.y;
	vertices[index++] = norm.z;

	// Add the rest of the vertices to data buffer.
    for(std::vector<Corner*>::iterator it = this->mCorners.begin(); it != this->mCorners.end(); ++it) {
		// Add to the next point to the array.
		// -- Position
		Vector3 vector = (*it)->vec3();

		vertices[index++] = vector.x;
		vertices[index++] = vector.y;
		vertices[index++] = vector.z;

		// -- Normal
		Vector3 normal = Vector3::UNIT_Y;

		vertices[index++] = normal.x;
		vertices[index++] = normal.y;
		vertices[index++] = normal.z;
	}

	// Define vertices color.
	RenderSystem* rs = Root::getSingleton().getRenderSystem();
	RGBA* colors = new RGBA[vertCount];

	for(size_t i = 0; i < vertCount; ++i)
		rs->convertColourValue(ColourValue(0.0f + 0.175f*i, 0.2f, 1.0f - 0.175f*i), colors + i);

	// Define the triangles.
	size_t faceCount = vertCount - 1; // Face count = vertCount - cent

	size_t center = 0;
	size_t last   = 1; //collin was here
	size_t curr   = 2;

	unsigned short* faces = new unsigned short[faceCount*3];

	index = 0;

	for(size_t i = 0; i < faceCount; ++i) {
		assert(last < vertCount && curr < vertCount); // Panic check

		faces[index++] = center;
		faces[index++] = curr;
		faces[index++] = last;

		last = curr++;

		if(curr >= vertCount) curr = 1;
	}

	// All information has been generated, move into mesh structures.
	//   Note: Currently does not implement or used any sort of shared
	//     vertices. This is intentional and should be changed at the 
	//     soonest conveienence. IE -- Never. ;P
	tileMesh->useSharedVertices = false;
	tileMesh->vertexData = new VertexData();
	tileMesh->vertexData->vertexCount = vertCount;

	// Create memory footprint for vertex data.
	size_t offset = 0;
	VertexDeclaration* decl = tileMesh->vertexData->vertexDeclaration;

	// Position and normal buffer.
	// -- Position
	decl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
	offset += VertexElement::getTypeSize(VET_FLOAT3);

	// -- Normal
	decl->addElement(0, offset, VET_FLOAT3, VES_NORMAL);
	offset += VertexElement::getTypeSize(VET_FLOAT3);

	// Allocate a vertex buffer for a number of vertices and vertex size.
	HardwareVertexBufferSharedPtr vertBuff = 
		HardwareBufferManager::getSingleton().createVertexBuffer(
			offset, // Size of a vertex, in bytes.
			tileMesh->vertexData->vertexCount,
			HardwareBuffer::HBU_STATIC_WRITE_ONLY);

	// Write our data to vertex buffer.
	vertBuff->writeData(0, vertBuff->getSizeInBytes(), vertices, true);

	// Set the buffer's bind location.
	VertexBufferBinding* vertBind = tileMesh->vertexData->vertexBufferBinding;
	vertBind->setBinding(0, vertBuff);

	// Color buffer for vertices
	offset = 0;
	decl->addElement(1, offset, VET_COLOUR, VES_DIFFUSE);
	offset += VertexElement::getTypeSize(VET_COLOUR);

	// Allocate a new buffer for colors.
	vertBuff = HardwareBufferManager::getSingleton().createVertexBuffer(
			offset, // Size of a vertex, in bytes.
			tileMesh->vertexData->vertexCount,
			HardwareBuffer::HBU_STATIC_WRITE_ONLY);

	// Write color data to buffer.
	vertBuff->writeData(0, vertBuff->getSizeInBytes(), colors, true);

	// Set the color buffer's bind location
	vertBind->setBinding(1, vertBuff);

	// Allocate a buffer for the index information
	HardwareIndexBufferSharedPtr indexBuff = HardwareBufferManager::getSingleton().createIndexBuffer(
		HardwareIndexBuffer::IT_16BIT,
		faceCount*3,
		HardwareBuffer::HBU_STATIC_WRITE_ONLY);

	// Write data to the buffer.
	indexBuff->writeData(0, indexBuff->getSizeInBytes(), faces, true);

	// Finalize submesh.
	tileMesh->indexData->indexBuffer = indexBuff;
	tileMesh->indexData->indexCount = faceCount*3;
	tileMesh->indexData->indexStart = 0;

	// Deallocate the vertex and face arrays.
	if(vertices) delete[] vertices;
	if(faces) delete[] faces;
}
Ogre::MeshPtr LodOutsideMarker::createConvexHullMesh(const String& meshName, const String& resourceGroupName)
{
    // Based on the wiki sample: http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Generating+A+Mesh

    // Resource with given name should not exist!
    assert(MeshManager::getSingleton().getByName(meshName).isNull());

    generateHull(); // calculate mHull triangles.

    // Convex hull can't be empty!
    assert(!mHull.empty());

    MeshPtr mesh = MeshManager::getSingleton().createManual(meshName, resourceGroupName, NULL);
    SubMesh* subMesh = mesh->createSubMesh();

    vector<Real>::type vertexBuffer;
    vector<unsigned short>::type indexBuffer;
    // 3 position/triangle * 3 Real/position
    vertexBuffer.reserve(mHull.size() * 9);
    // 3 index / triangle
    indexBuffer.reserve(mHull.size() * 3);
    int id=0;
    // min & max position
    Vector3 minBounds(std::numeric_limits<Real>::max(), std::numeric_limits<Real>::max(), std::numeric_limits<Real>::max());
    Vector3 maxBounds(std::numeric_limits<Real>::min(), std::numeric_limits<Real>::min(), std::numeric_limits<Real>::min());

    for (size_t i = 0; i < mHull.size(); i++) {
        assert(!mHull[i].removed);
        for(size_t n = 0; n < 3; n++){
            indexBuffer.push_back(id++);
            vertexBuffer.push_back(mHull[i].vertex[n]->position.x);
            vertexBuffer.push_back(mHull[i].vertex[n]->position.y);
            vertexBuffer.push_back(mHull[i].vertex[n]->position.z);
            minBounds.x = std::min<Real>(minBounds.x, mHull[i].vertex[n]->position.x);
            minBounds.y = std::min<Real>(minBounds.y, mHull[i].vertex[n]->position.y);
            minBounds.z = std::min<Real>(minBounds.z, mHull[i].vertex[n]->position.z);
            maxBounds.x = std::max<Real>(maxBounds.x, mHull[i].vertex[n]->position.x);
            maxBounds.y = std::max<Real>(maxBounds.y, mHull[i].vertex[n]->position.y);
            maxBounds.z = std::max<Real>(maxBounds.z, mHull[i].vertex[n]->position.z);
        }
    }

    /// Create vertex data structure for 8 vertices shared between submeshes
    mesh->sharedVertexData = new VertexData();
    mesh->sharedVertexData->vertexCount = mHull.size() * 3;

    /// Create declaration (memory format) of vertex data
    VertexDeclaration* decl = mesh->sharedVertexData->vertexDeclaration;
    size_t offset = 0;
    // 1st buffer
    decl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
    offset += VertexElement::getTypeSize(VET_FLOAT3);

    /// Allocate vertex buffer of the requested number of vertices (vertexCount) 
    /// and bytes per vertex (offset)
    HardwareVertexBufferSharedPtr vbuf = 
        HardwareBufferManager::getSingleton().createVertexBuffer(
        offset, mesh->sharedVertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
    /// Upload the vertex data to the card
    vbuf->writeData(0, vbuf->getSizeInBytes(), &vertexBuffer[0], true);

    /// Set vertex buffer binding so buffer 0 is bound to our vertex buffer
    VertexBufferBinding* bind = mesh->sharedVertexData->vertexBufferBinding; 
    bind->setBinding(0, vbuf);

    /// Allocate index buffer of the requested number of vertices (ibufCount) 
    HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton().
        createIndexBuffer(
        HardwareIndexBuffer::IT_16BIT, 
        indexBuffer.size(), 
        HardwareBuffer::HBU_STATIC_WRITE_ONLY);

    /// Upload the index data to the card
    ibuf->writeData(0, ibuf->getSizeInBytes(), &indexBuffer[0], true);

    /// Set parameters of the submesh
    subMesh->useSharedVertices = true;
    subMesh->indexData->indexBuffer = ibuf;
    subMesh->indexData->indexCount = indexBuffer.size();
    subMesh->indexData->indexStart = 0;

    /// Set bounding information (for culling)
    mesh->_setBounds(AxisAlignedBox(minBounds, maxBounds));
    mesh->_setBoundingSphereRadius(maxBounds.distance(minBounds) / 2.0f);

    /// Set material to transparent blue
    subMesh->setMaterialName("Examples/TransparentBlue50");

    /// Notify -Mesh object that it has been loaded
    mesh->load();

    return mesh;
}
static MeshPtr importObject(QDataStream &stream)
{
    using namespace Ogre;

    QVector4D bbMin, bbMax;
    stream >> bbMin >> bbMax;

    float distance, distanceSquared; // Here's a bug for you: writes "double"'s instead of floats
    stream >> distanceSquared >> distance;

    MeshPtr ogreMesh = MeshManager::getSingleton().createManual("conversion",
                                                               ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

    int vertexCount, indexCount;
    stream >> vertexCount >> indexCount;

    VertexData *vertexData = new VertexData();
    ogreMesh->sharedVertexData = vertexData;

    LogManager::getSingleton().logMessage("Reading geometry...");
    VertexDeclaration* decl = vertexData->vertexDeclaration;
    VertexBufferBinding* bind = vertexData->vertexBufferBinding;
    unsigned short bufferId = 0;

    // Information for calculating bounds
    Vector3 min = Vector3::ZERO, max = Vector3::UNIT_SCALE, pos = Vector3::ZERO;
    Real maxSquaredRadius = -1;
    bool firstVertex = true;

    /*
      Create a vertex definition for our buffer
      */
    size_t offset = 0;

    const VertexElement &positionElement = decl->addElement(bufferId, offset, VET_FLOAT3, VES_POSITION);
    offset += VertexElement::getTypeSize(VET_FLOAT3);

    const VertexElement &normalElement = decl->addElement(bufferId, offset, VET_FLOAT3, VES_NORMAL);
    offset += VertexElement::getTypeSize(VET_FLOAT3);

    // calculate how many vertexes there actually are
    vertexData->vertexCount = vertexCount;

    // Now create the vertex buffer
    HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton().
            createVertexBuffer(offset, vertexData->vertexCount,
                               HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);

    // Bind it
    bind->setBinding(bufferId, vbuf);

    // Lock it
    unsigned char *pVert = static_cast<unsigned char*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));
    unsigned char *pVertStart = pVert;

    QVector<float> positions;
    positions.reserve(vertexCount * 3);

    // Iterate over all children (vertexbuffer entries)
    for (int i = 0; i < vertexCount; ++i) {
        float *pFloat;

        QVector4D vertex;
        stream >> vertex;
		vertex.setZ(vertex.z() * -1);

        /* Copy over the position */
        positionElement.baseVertexPointerToElement(pVert, &pFloat);
        *(pFloat++) = (float)vertex.x();
        *(pFloat++) = (float)vertex.y();
        *(pFloat++) = (float)vertex.z();

        positions.append(vertex.x());
        positions.append(vertex.y());
        positions.append(vertex.z());

        /* While we're at it, calculate the bounding sphere */
        pos.x = vertex.x();
        pos.y = vertex.y();
        pos.z = vertex.z();

        if (firstVertex) {
            min = max = pos;
            maxSquaredRadius = pos.squaredLength();
            firstVertex = false;
        } else {
            min.makeFloor(pos);
            max.makeCeil(pos);
            maxSquaredRadius = qMax(pos.squaredLength(), maxSquaredRadius);
        }

        pVert += vbuf->getVertexSize();
    }

    // Set bounds
    const AxisAlignedBox& currBox = ogreMesh->getBounds();
    Real currRadius = ogreMesh->getBoundingSphereRadius();
    if (currBox.isNull())
    {
        //do not pad the bounding box
        ogreMesh->_setBounds(AxisAlignedBox(min, max), false);
        ogreMesh->_setBoundingSphereRadius(Math::Sqrt(maxSquaredRadius));
    }
    else
    {
        AxisAlignedBox newBox(min, max);
        newBox.merge(currBox);
        //do not pad the bounding box
        ogreMesh->_setBounds(newBox, false);
        ogreMesh->_setBoundingSphereRadius(qMax(Math::Sqrt(maxSquaredRadius), currRadius));
    }

    /*
       Create faces
     */
    // All children should be submeshes
    SubMesh* sm = ogreMesh->createSubMesh();
    sm->setMaterialName("clippingMaterial");
    sm->operationType = RenderOperation::OT_TRIANGLE_LIST;
    sm->useSharedVertices = true;

    // tri list
    sm->indexData->indexCount = indexCount;

    // Allocate space
    HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton().
            createIndexBuffer(
                HardwareIndexBuffer::IT_16BIT,
                sm->indexData->indexCount,
                HardwareBuffer::HBU_DYNAMIC,
                false);
    sm->indexData->indexBuffer = ibuf;

    unsigned short *pShort = static_cast<unsigned short*>(ibuf->lock(HardwareBuffer::HBL_DISCARD));

    QVector<EdgeData::Triangle> triangles(indexCount / 3);

    for (int i = 0; i < indexCount / 3; ++i) {
        quint16 i1, i2, i3;

        stream >> i1 >> i2 >> i3;
        *pShort++ = i1;
        *pShort++ = i2;
        *pShort++ = i3;

        triangles[i].vertIndex[0] = i1;
        triangles[i].vertIndex[1] = i2;
        triangles[i].vertIndex[2] = i3;

    }

    /* Recalculate the vertex normals */
    Vector4 *faceNormals = (Vector4*)_aligned_malloc(sizeof(Vector4) * triangles.size(), 16);

    OptimisedUtil *util = OptimisedUtil::getImplementation();
    util->calculateFaceNormals(positions.constData(),
                               triangles.data(),
                               faceNormals,
                               indexCount / 3);

	 // Iterate over all children (vertexbuffer entries)
	pVert = pVertStart;
    for (int i = 0; i < vertexCount; ++i) {
        float *pFloat;

		Vector3 normal = Vector3::ZERO;
		
		int count = 0;

		/* Search for all faces that use this vertex */
		for (int j = 0; j < triangles.size(); ++j) {
			if (triangles[j].vertIndex[0] == i 
				|| triangles[j].vertIndex[1] == i 
				|| triangles[j].vertIndex[2] == i) {
				normal.x += faceNormals[j].x / faceNormals[j].w;
				normal.y += faceNormals[j].y / faceNormals[j].w;
				normal.z += faceNormals[j].z / faceNormals[j].w;
				count++;
			}
		}

		normal.normalise();

        /* Copy over the position */
		normalElement.baseVertexPointerToElement(pVert, &pFloat);
        *(pFloat++) = normal.x;
        *(pFloat++) = normal.y;
        *(pFloat++) = normal.z;
		
        pVert += vbuf->getVertexSize();
    }

    _aligned_free(faceNormals);

    vbuf->unlock();
    ibuf->unlock();

    return ogreMesh;
}
// Generate normals for polygon meshes
void IndexedGeometry::createIndexedFaceSet()
{
	if (_coords.empty())
		throw std::runtime_error("No coordinates given.");

	if (_coordIndex.empty())
		throw std::runtime_error("No coordinate index given.");

	MeshPtr mesh = MeshManager::getSingleton().createManual(_name, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
	SubMesh *sub = mesh->createSubMesh();

	bool hasTextureCoordinates = !_texCoords.empty();
	bool hasPointColors = !_colors.empty() && _colorPerVertex;
	bool hasPointNormals = !_normals.empty() && _normalPerVertex;
	bool hasCellColors = !_colors.empty() && !hasPointColors;
	bool hasCellNormals = !_normals.empty() && !hasPointNormals;
	bool calcPointNormals = _normals.empty() && _normalPerVertex;

	std::vector<face> faces;
	face f;
	for (std::vector<int>::const_iterator I=_coordIndex.begin(); I !=_coordIndex.end(); ++I) {
		if (*I == -1) {
			faces.resize(faces.size()+1);
			faces.back().indices.swap(f.indices);
		} else
			f.indices.push_back(I - _coordIndex.begin());
	}
	if (!f.indices.empty()) {
		faces.resize(faces.size()+1);
		faces.back().indices.swap(f.indices);
	}


	std::vector<vertex> vertices;
	std::vector<triangle> triangles;


	VertMap vertexMap;

	// triangulate and expand vertices
	for (std::vector<face>::const_iterator f=faces.begin(), e=faces.end(); f!=e; ++f) {
		int faceNr = f - faces.begin();
		int triVertNr = 0;
		int triVerts[2] = { -1, -1 };
		for (std::vector<int>::const_iterator i = f->indices.begin(), e=f->indices.end(); i!=e; ++i, ++triVertNr) {
			int triVertNr = i - f->indices.begin();
			int index = *i;

			vertex vert;

			// get full indices for vertex data
			vert.pos = _coordIndex[index];
			vert.normal = !_normals.empty() ? getIndex(_coordIndex, _normalIndex,
				_normalPerVertex, faceNr, index) : 0;
			vert.colour = !_colors.empty() ? getIndex(_coordIndex, _colorIndex,
				_colorPerVertex, faceNr, index) : 0;
			vert.tc = hasTextureCoordinates ? getIndex(_coordIndex, _texCoordIndex,
				true, faceNr, index) : 0;

			// avoid duplication
			//int nvert = vertexMap.size();
			//int &vpos = vertexMap[vert];
			//if (nvert != vertexMap.size()) {
				int vpos = vertices.size();
				vertices.push_back(vert);
			//}

			// emit triangle (maybe)
			if (triVertNr == 0)
				triVerts[0] = vpos;
			else if (triVertNr == 1)
				triVerts[1] = vpos;
			else {
				triangle t;
				t.vertices[0] = triVerts[0];
				t.vertices[1] = triVerts[1];
				t.vertices[2] = vpos;

				if (!_ccw)
					std::swap(t.vertices[1], t.vertices[2]);

				triangles.push_back(t);

				triVerts[1] = vpos;
			}
		}
	}
	
	// createOgreMesh
	int nvertices = vertices.size();
	int nfaces = triangles.size();

	VertexData* vertexData = new VertexData();
	sub->vertexData = vertexData;

	IndexData* indexData = sub->indexData;
	VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
	size_t currOffset = 0;
	
	// positions
	vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_POSITION);
	currOffset += VertexElement::getTypeSize(VET_FLOAT3);

	if (hasPointNormals)
	{
		// normals
		vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_NORMAL);
		currOffset += VertexElement::getTypeSize(VET_FLOAT3);

	}
	// two dimensional texture coordinates
	if (hasTextureCoordinates)
	{
		vertexDecl->addElement(0, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
		currOffset += VertexElement::getTypeSize(VET_FLOAT2);
	}

	std::cout << std::endl;

	// allocate index buffer
	indexData->indexCount = nfaces * 3;
	indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(HardwareIndexBuffer::IT_16BIT, indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
	HardwareIndexBufferSharedPtr iBuf = indexData->indexBuffer;
	unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(HardwareBuffer::HBL_DISCARD));

	std::cout << triangles.size() << ": ";
	for(std::vector<triangle>::const_iterator T = triangles.begin(); T != triangles.end(); T++)
	{
		const triangle &t = (*T);
		*pIndices++ = t.vertices[0];
		*pIndices++ = t.vertices[1];
		*pIndices++ = t.vertices[2];
		std::cout << t.vertices[0] << " " << t.vertices[1] << " "  << t.vertices[2] << " ";
	}
	std::cout << std::endl;

	// allocate the vertex buffer
	vertexData->vertexCount = nvertices;
	HardwareVertexBufferSharedPtr vBuf = HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(0), vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
	VertexBufferBinding* binding = vertexData->vertexBufferBinding;
	binding->setBinding(0, vBuf);
	float* pVertex = static_cast<float*>(vBuf->lock(HardwareBuffer::HBL_DISCARD));

	AxisAlignedBox aabox;
	std::cout << vertices.size() << ": ";
	for(std::vector<vertex>::const_iterator V = vertices.begin(); V != vertices.end(); V++)
	{

		const vertex &v = (*V);
		SFVec3f pos = _coords.at(v.pos);
		*pVertex++ = pos.x;
		*pVertex++ = pos.y;
		*pVertex++ = pos.z;
		aabox.merge(Vector3(pos.x, pos.y, pos.z));
		std::cout << pos.x << " " << pos.y << " "  << pos.z << " " << std::endl;
		//std::cout << v.pos << " ";
		if (hasPointNormals)
		{
			const SFVec3f normal = _normals.at(v.normal);
			*pVertex++ = normal.x;
			*pVertex++ = normal.y;
			*pVertex++ = normal.z;
		}
	}

std::cout << std::endl;
	// Unlock
	vBuf->unlock();
	iBuf->unlock();

	sub->useSharedVertices = false;

	// the original code was missing this line:
	mesh->_setBounds(aabox);
	mesh->_setBoundingSphereRadius((aabox.getMaximum()-aabox.getMinimum()).length()/2.0);
	// this line makes clear the mesh is loaded (avoids memory leaks)
	mesh->load();

}
Beispiel #14
0
void createSphereMesh(const String &name, const float radius, const int slices, const int stacks)
{
  MeshPtr mesh = MeshManager::getSingleton().createManual(name, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
  mesh->sharedVertexData = new VertexData();
  mesh->_setBounds(AxisAlignedBox(Vector3(-radius, -radius, -radius), Vector3(radius, radius, radius)));
  mesh->_setBoundingSphereRadius(radius);

  VertexData *vertexData = mesh->sharedVertexData;
  vertexData->vertexDeclaration->addElement(0, 0, VET_FLOAT3, VES_POSITION);
  vertexData->vertexDeclaration->addElement(1, 0, VET_FLOAT3, VES_NORMAL);
  vertexData->vertexCount = slices * (stacks + 1);
  HardwareVertexBufferSharedPtr positionBuffer = HardwareBufferManager::getSingleton().createVertexBuffer(
      vertexData->vertexDeclaration->getVertexSize(0),
      vertexData->vertexCount,
      HardwareBuffer::HBU_STATIC_WRITE_ONLY);
  HardwareVertexBufferSharedPtr normalBuffer = HardwareBufferManager::getSingleton().createVertexBuffer(
      vertexData->vertexDeclaration->getVertexSize(1),
      vertexData->vertexCount,
      HardwareBuffer::HBU_STATIC_WRITE_ONLY);
  float *position = static_cast<float *>(positionBuffer->lock(HardwareBuffer::HBL_DISCARD));
  float *normal = static_cast<float *>(normalBuffer->lock(HardwareBuffer::HBL_DISCARD));
  for (int ring = 0; ring <= stacks; ring++) {
    float r = radius * sinf(ring * Math::PI / stacks);
    float y = radius * cosf(ring * Math::PI / stacks);
    for (int segment = 0; segment < slices; segment++) {
      float x = r * sinf(segment * 2 * Math::PI / slices);
      float z = r * cosf(segment * 2 * Math::PI / slices);
      *position++ = x;
      *position++ = y;
      *position++ = z;
      Vector3 tmp = Vector3(x, y, z).normalisedCopy();
      *normal++ = tmp.x;
      *normal++ = tmp.y;
      *normal++ = tmp.z;
    }
  }
  positionBuffer->unlock();
  normalBuffer->unlock();
  vertexData->vertexBufferBinding->setBinding(0, positionBuffer);
  vertexData->vertexBufferBinding->setBinding(1, normalBuffer);

  SubMesh *subMesh = mesh->createSubMesh();
  subMesh->useSharedVertices = true;

  IndexData *indexData = subMesh->indexData;
  indexData->indexCount = 6 * slices * stacks;
  HardwareIndexBufferSharedPtr indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(
      HardwareIndexBuffer::IT_16BIT,
      indexData->indexCount,
      HardwareBuffer::HBU_STATIC_WRITE_ONLY);
  unsigned short *index = static_cast<unsigned short *>(indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
  unsigned short i = 0;
  for (int ring = 0; ring < stacks; ring++) {
    for (int segment = 0; segment < slices - 1; segment++) {
      *index++ = i;
      *index++ = i + slices;
      *index++ = i + slices + 1;
      *index++ = i;
      *index++ = i + slices + 1;
      *index++ = i + 1;
      i++;
    }
    *index++ = i;
    *index++ = i + slices;
    *index++ = i + 1;
    *index++ = i;
    *index++ = i + 1;
    *index++ = i + 1 - slices;
    i++;
  }
  indexBuffer->unlock();
  indexData->indexBuffer = indexBuffer;

  mesh->load();
}