//==========================================================================
CAABBox CAABBox::transformAABBox(const CMatrix &mat, const CAABBox &box)
{
	// TODO : optimize this a bit if possible...
	CAABBox result;

	/* OMG. Old code was false!!
		if we have ht= M * h
		then CVector(-ht.x, ht.y, ht.z) != M * CVector(-h.x, h.y, h.z) !!!!
	*/
	// compute corners.
	CVector	p[8];
	CVector	min= box.getMin();
	CVector	max= box.getMax();
	p[0].set(min.x, min.y, min.z);
	p[1].set(max.x, min.y, min.z);
	p[2].set(min.x, max.y, min.z);
	p[3].set(max.x, max.y, min.z);
	p[4].set(min.x, min.y, max.z);
	p[5].set(max.x, min.y, max.z);
	p[6].set(min.x, max.y, max.z);
	p[7].set(max.x, max.y, max.z);
	CVector tmp;
	min = max = mat * p[0];
	// transform corners.
	for(uint i=1;i<8;i++)
	{
		tmp= mat * p[i];
		min.minof(min, tmp);
		max.maxof(max, tmp);
	}

	result.setMinMax(min, max);

	return result;
}
Esempio n. 2
0
bool CActor::checkAttack( CVectorD &pos )
{
	/*
		if we're close to an actor then attack them
	*/
	CAABBox	box;
	box.setCenter(CVector(_x*0.001f, _y*0.001f, 0.0f));
	box.setHalfSize(CVector(5.0f, 5.0f, 1.0f));

	CMoveManager::Grid.clearSelection();
	CMoveManager::Grid.select(box);

	CMoveManager::TObstacleGrid::CIterator	it;
	for (it=CMoveManager::Grid.begin(); it!=CMoveManager::Grid.end(); ++it)
	{
		CObstacle		&other = (*it);

		// attacks player if close to me
		CVector	d = pos-other.Position;
		d.z = 0.0f;
		if (other.Id.getType() == RYZOMID::player && d.norm() <= _AttackDistance)
		{
			nlinfo("Actor <%s> attacks player because _AttackDistance = %f and separation = %f", _name.c_str(), _AttackDistance, d.norm());
			doFight(other.Id);
			return true;
		}
	}
	return false;
}
Esempio n. 3
0
///////////////
// FUNCTIONS //
///////////////
//-----------------------------------------------
// initPACS :
// Initialize PACS.
//-----------------------------------------------
void initPACS(const char* rbank, const char* gr, NLMISC::IProgressCallback &/* progress */)
{
	// Check old PACS is well released.
	nlassertex(RB==0,   ("RB should be Null before the init."));
	nlassertex(GR==0,   ("GR should be Null before the init."));
	nlassertex(PACS==0, ("PACS should be Null before the init."));

	if(rbank != 0 && gr != 0)
	{
		RB = NLPACS::URetrieverBank::createRetrieverBank(rbank, false);
		GR = NLPACS::UGlobalRetriever::createGlobalRetriever(gr, RB);
		if (GR)
		{
			CAABBox		cbox = GR->getBBox();

			uint gw = (uint)(cbox.getHalfSize().x*2.0 / RYZOM_ENTITY_SIZE_MAX) + 1;
			uint gh = (uint)(cbox.getHalfSize().y*2.0 / RYZOM_ENTITY_SIZE_MAX) + 1;


			PACS = UMoveContainer::createMoveContainer(GR, gw, gh, RYZOM_ENTITY_SIZE_MAX, 2);
		}
		else
			nlwarning("Could not create global retriever for %s, %s", rbank, gr);
	}

	// Try to create a PACS with another method.
	if(PACS == 0)
		PACS = UMoveContainer::createMoveContainer(15000.0, -25000.0, 20000.0, -20000.0, 16, 16, RYZOM_ENTITY_SIZE_MAX, 2);

	// Set the static world image.
	if(PACS)
		PACS->setAsStatic(staticWI);
	else
		nlwarning("initPACS: cannot create PACS at all.");
}// initPACS //
CAABBox	NLPACS::CSurfElement::getBBox() const
{
	CAABBox	box;
	box.setCenter((*Vertices)[Tri[0]]);
	box.extend((*Vertices)[Tri[1]]);
	box.extend((*Vertices)[Tri[2]]);
	return box;
}
//==========================================================================
void	CAABBox::computeIntersection(const CAABBox &b1, const CAABBox &b2)
{
	CVector	min1 = b1.getMin(), max1 = b1.getMax(),
			min2 = b2.getMin(), max2 = b2.getMax();
	CVector	minr, maxr;

	// don't test if intersect or not.
	maxr.minof(max1, max2);
	minr.maxof(min1, min2);

	setMinMax(minr, maxr);
}
// ***************************************************************************
bool			CAABBox::intersect(const CAABBox &box) const
{
	CVector	mina = getMin(), maxa = getMax(),
			minb = box.getMin(), maxb = box.getMax();

	return ! ( mina.x > maxb.x ||
			   mina.y > maxb.y ||
			   mina.z > maxb.z ||
			   minb.x > maxa.x ||
			   minb.y > maxa.y ||
			   minb.z > maxa.z);
}
static CAABBox	getSnappedBBox(CVector v0, CVector v1, CVector v2, const CAABBox &bbox)
{
	snapAccuracyBit(v0);
	snapAccuracyBit(v1);
	snapAccuracyBit(v2);

	CAABBox	box;

	box.setCenter(v0);
	box.extend(v1);
	box.extend(v2);

	return box;
}
// ***************************************************************************
NLMISC::CAABBox			CVisualCollisionMesh::computeWorldBBox(const CMatrix &instanceMatrix)
{
	CAABBox		ret;
	if(!_Vertices.empty())
	{
		ret.setCenter(instanceMatrix*_Vertices[0]);
		for(uint i=1;i<_Vertices.size();i++)
		{
			ret.extend(instanceMatrix*_Vertices[i]);
		}
	}

	return ret;
}
CAABBox	getZoneBBoxById(uint16 id)
{
	CAABBox		bbox;
	uint		x, y;
	const float	zdim = 160.0f;

	x = id%256;
	y = id/256;
	bbox.setMinMax(CVector(zdim*x,		-zdim*(y+1),	-10000.0f),
				   CVector(zdim*(x+1),	-zdim*y,		+10000.0f));


	return bbox;
}
CAABBox	NLPACS::CZoneTessellation::computeBBox() const
{
	CAABBox		zbox;
	bool		set = false;
	uint		i;

	if (_Vertices.size() == 0)
		return zbox;

	zbox.setCenter(_Vertices[0]);

	for (i=1; i<_Vertices.size(); ++i)
		zbox.extend(_Vertices[i]);

	return zbox;
}
	// If the bbox has a null size, then mark it void
	void removeVoid() 
	{ 
		if (!IsVoid && Box.getHalfSize() == CVector::Null)
		{
			IsVoid = true;
		}
	}
Esempio n. 12
0
// ***************************************************************************
void	CTransformShape::getLightHotSpotInWorld(CVector &modelPos, float &modelRadius) const
{
	/*
	// get the untransformed bbox from the model.
	CAABBox		bbox;
	getAABBox(bbox);
	// get transformed center pos of bbox
	modelPos= getWorldMatrix() * bbox.getCenter();
	// If the model is a big lightable, must take radius from aabbox, else suppose 0 radius.
	if(isBigLightable())
	{
		// get size of the bbox (bounding sphere)
		modelRadius= bbox.getRadius();
	}
	else
	{
		// Assume 0 radius => faster computeLinearAttenuation()
		modelRadius= 0;
	}
	*/

	// This method works well for Big Trees.
	// TODO: generalize, saving a LightHotSpot per shape.

	// get pos of object. Ie the hotSpot is the pivot.
	modelPos= getWorldMatrix().getPos();
	// If the model is a big lightable, must take radius from aabbox, else suppose 0 radius.
	if(isBigLightable())
	{
		// get the untransformed bbox from the model.
		CAABBox		bbox;
		getAABBox(bbox);
		// get size of the bbox (bounding sphere)
		modelRadius= bbox.getRadius();
	}
	else
	{
		// Assume 0 radius => faster computeLinearAttenuation()
		modelRadius= 0;
	}

}
void	computeSurfaceQuadTree(CInteriorSurface &surface, CSurfaceQuadTree &quad)
{
	uint	i, j;

	CAABBox	box;
	bool	first = true;
	for (i=0; i<surface.Faces.size(); ++i)
	{
		for (j=0; j<3; ++j)
		{
			const CVector	&v = surface.CollisionMeshBuild->Vertices[surface.CollisionMeshBuild->Faces[surface.Faces[i]].V[j]];
			if (first)
				box.setCenter(v), first=false;
			else
				box.extend(v);
		}
	}

	quad.clear();
	quad.init(4.0f, 6, box.getCenter(), std::max(box.getHalfSize().x, box.getHalfSize().y));

	for (i=0; i<surface.Faces.size(); ++i)
	{
		for (j=0; j<3; ++j)
		{
			const CVector	&v = surface.CollisionMeshBuild->Vertices[surface.CollisionMeshBuild->Faces[surface.Faces[i]].V[j]];
			quad.addVertex(v);
		}
	}

	quad.compile();
}
Esempio n. 14
0
/*
 *		render()
 */
void	CPrimChecker::render(CPrimZone *zone, uint8 bits)
{
	if (zone->VPoints.size() < 3)
		return;

	string	name;
	if (zone->getPropertyByName("name", name) && Verbose)
		nlinfo("Rendering CPrimZone '%s'", name.c_str());

	// get the bouding box of the CPrimZone
	CAABBox	box;

	box.setCenter(zone->VPoints[0]);
	box.setHalfSize(CVector::Null);

	uint	i;
	for (i=1; i<zone->VPoints.size(); ++i)
		box.extend(zone->VPoints[i]);

	sint32	xmin, ymin, xmax, ymax;

	xmin = (sint32)(floor(box.getMin().x));
	ymin = (sint32)(floor(box.getMin().y));

	xmax = (sint32)(ceil(box.getMax().x));
	ymax = (sint32)(ceil(box.getMax().y));

	// Fill grid with points that belong to the CPrimZone
	sint32	x, y;
	for (y=ymin; y<=ymax; ++y)
		for (x=xmin; x<=xmax; ++x)
			if (zone->contains(CVector((float)x, (float)y, 0.0f)))
				_Grid.set(x, y, bits);
}
Esempio n. 15
0
// ***************************************************************************
bool					CVisualCollisionMesh::build(const std::vector<CVector> &vertices, const std::vector<uint32> &triangles, CVertexBuffer &vbForShadowRender)
{
	/* ***********************************************
	 *	WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
	 *	It can be loaded/called through CAsyncFileManager for instance
	 * ***********************************************/

	uint	i;
	// if no vertices, or no triangles, abort
	if(vertices.empty())
		return false;
	if(triangles.empty())
		return false;
	// vertices and triangles id are stored in uint16 form. so their should not be more than 65535*3 indices
	if(vertices.size()>65535 || triangles.size()>65535*3)
		return false;

	// copy
	_Vertices= vertices;

	// compress indexes to 16 bits
	_Triangles.resize(triangles.size());
	for(i=0;i<_Triangles.size();i++)
		_Triangles[i]= (uint16)triangles[i];

	// Build the Local bbox for this col mesh
	CAABBox		localBBox;
	localBBox.setCenter(vertices[0]);
	for(i=1;i<vertices.size();i++)
		localBBox.extend(vertices[i]);

	// Build the Static Grid
	uint	numTris= (uint)triangles.size()/3;
	_QuadGrid.create(16, numTris, localBBox);
	// Add all triangles
	for(i=0;i<numTris;i++)
	{
		CAABBox		bb;
		bb.setCenter(_Vertices[_Triangles[i*3+0]]);
		bb.extend(_Vertices[_Triangles[i*3+1]]);
		bb.extend(_Vertices[_Triangles[i*3+2]]);
		_QuadGrid.add(i, bb);
	}
	// compile
	_QuadGrid.compile();


	// Keep a RefPtr on the AGP vertex Buffer for shadow receiving
	_VertexBuffer= &vbForShadowRender;


	return true;
}
CAABBox CAABBox::computeAABBoxUnion(const CAABBox &b1, const CAABBox &b2)
{
	CAABBox result;
	CVector min, max;
	CVector min1 = b1.getMin()
		    ,max1 = b1.getMax()
			,min2 = b2.getMin()
		    ,max2 = b2.getMax();
	max.maxof(max1, max2);
	min.minof(min1, min2);
	result.setMinMax(min, max);
	return result;
}
Esempio n. 17
0
// ***************************************************************************
void	CQuadGridClipClusterQTreeNode::init(CQuadGridClipCluster *owner, uint level, bool rootNode, const NLMISC::CAABBox &pivot)
{
	Owner= owner;
	RootNode= rootNode;
	PivotBBox= pivot;

	// If not a leaf, create sons
	if(level>0)
	{
		LeafNode= false;

		// split pivot for sons
		CAABBox	pivotSon;
		pivotSon.setSize(PivotBBox.getHalfSize());
		float	xMin= PivotBBox.getMin().x/2;
		float	yMin= PivotBBox.getMin().y/2;
		float	xMax= PivotBBox.getMax().x/2;
		float	yMax= PivotBBox.getMax().y/2;
		float	xCenter= PivotBBox.getCenter().x/2;
		float	yCenter= PivotBBox.getCenter().y/2;
		// LeftDown
		pivotSon.setCenter( CVector(xMin+xCenter,yMin+yCenter,0) );
		Sons[NL3D_QCC_LEFT_DOWN]= new CQuadGridClipClusterQTreeNode;
		Sons[NL3D_QCC_LEFT_DOWN]->init(owner, level-1, false, pivotSon);
		// RightDown
		pivotSon.setCenter( CVector(xMax+xCenter,yMin+yCenter,0) );
		Sons[NL3D_QCC_RIGHT_DOWN]= new CQuadGridClipClusterQTreeNode;
		Sons[NL3D_QCC_RIGHT_DOWN]->init(owner, level-1, false, pivotSon);
		// LeftUp
		pivotSon.setCenter( CVector(xMin+xCenter,yMax+yCenter,0) );
		Sons[NL3D_QCC_LEFT_UP]= new CQuadGridClipClusterQTreeNode;
		Sons[NL3D_QCC_LEFT_UP]->init(owner, level-1, false, pivotSon);
		// RithgUp
		pivotSon.setCenter( CVector(xMax+xCenter,yMax+yCenter,0) );
		Sons[NL3D_QCC_RIGHT_UP]= new CQuadGridClipClusterQTreeNode;
		Sons[NL3D_QCC_RIGHT_UP]->init(owner, level-1, false, pivotSon);
	}
	else
	{
		LeafNode= true;
	}

	// Create the distMax list only if root or leaf. No models in interleaved branches.
	if( LeafNode)
		ListNode.Models.resize(Owner->_NumDistTotal);
}
Esempio n. 18
0
int main(int argc, char **argv)
{
	// Filter addSearchPath
	NLMISC::createDebug();
	InfoLog->addNegativeFilter("adding the path");

	createDebug();

	try
	{
		// Init
		init();

		uint	i, j, k;

		for (i=0; i<IGs.size(); ++i)
		{
			// load ig associated to the zone
			string			igName = IGs[i]+".ig";
			CIFile			igStream(CPath::lookup(igName));
			CInstanceGroup	ig;
			igStream.serial(ig);

			CAABBox			igBBox;
			bool			boxSet = false;

			nlinfo("Generating BBOX for %s", igName.c_str());

			// search in group for water instance
			for (j=0; j<ig._InstancesInfos.size(); ++j)
			{
				/*
				   Ben: c'est degueulasse, mais c'est les coders a la 3D, y savent pas coder
				   Hld: ouai, mais ca marche pas ton truc, alors p'tet qu'on sait pas coder mais toi non plus :p Special Dedicace to SupaGreg!
				string	shapeName = ig._InstancesInfos[j].Name+".shape";
				*/
				string	shapeName = ig._InstancesInfos[j].Name;
				if (CFile::getExtension (shapeName) == "")
					shapeName += ".shape";

				if (NonWaterShapes.find(shapeName) != NonWaterShapes.end())
					continue;

				string	shapeNameLookup = CPath::lookup (shapeName, false, false);
				if (!shapeNameLookup.empty())
				{
					CIFile			f;
					if (f.open (shapeNameLookup))
					{
						CShapeStream	shape;
						shape.serial(f);

						CWaterShape	*wshape = dynamic_cast<CWaterShape *>(shape.getShapePointer());
						if (wshape == NULL)
						{
							NonWaterShapes.insert(shapeName);
							continue;
						}

						CMatrix	matrix;
						ig.getInstanceMatrix(j, matrix);

						CPolygon			wpoly;
						wshape->getShapeInWorldSpace(wpoly);

						for (k=0; k<wpoly.Vertices.size(); ++k)
						{
							if (boxSet)
							{
								igBBox.extend(matrix * wpoly.Vertices[k]);
							}
							else
							{
								igBBox.setCenter(matrix * wpoly.Vertices[k]);
								boxSet = true;
							}
						}
					}
					else
					{
						nlwarning ("Can't load shape %s", shapeNameLookup.c_str());
					}
				}
				else
				{
					NonWaterShapes.insert(shapeName);
				}
			}

			if (boxSet)
			{
				Boxes.push_back(CIGBox(igName, igBBox));
				nlinfo("Bbox: (%.1f,%.1f)-(%.1f,%.1f)", igBBox.getMin().x, igBBox.getMin().y, igBBox.getMax().x, igBBox.getMax().y);
			}
		}

		COFile	output(Output);
		output.serialCont(Boxes);
	}
	catch (Exception &e)
	{
		fprintf (stderr,"main trapped an exception: '%s'\n", e.what ());
	}
#ifndef NL_DEBUG
	catch (...)
	{
		fprintf(stderr,"main trapped an unknown exception\n");
	}
#endif // NL_DEBUG

	return 0;
}
// ***************************************************************************
void	NLPACS::CZoneTessellation::build()
{
	sint	el;
	uint	i, j;

	NL3D::CLandscape	landscape;
	landscape.init();

	vector<CVector>				normals;

	vector<CVector>				vectorCheck;
	bool						useNoHmZones = true;

	{
		NL3D::CLandscape	landscapeNoHm;
		landscapeNoHm.init();

		//
		// load the 9 landscape zones
		//
		for (i=0; i<_ZoneIds.size(); ++i)
		{
			string	filename = getZoneNameById(_ZoneIds[i])+ZoneExt;
			CIFile	file(CPath::lookup(filename));
			CZone	zone;
			zone.serial(file);
			file.close();

			if (Verbose)
				nlinfo("use zone %s %d", filename.c_str(), zone.getZoneId());

			if (zone.getZoneId() != _ZoneIds[i])
			{
				nlwarning ("Zone %s ID is wrong. Abort.", filename.c_str());
				return;
			}
			landscape.addZone(zone);

			if (useNoHmZones)
			{
				string	filenameNH = getZoneNameById(_ZoneIds[i])+ZoneNHExt;
				string	loadZ = CPath::lookup(filenameNH, false, false);
				if (!loadZ.empty())
				{
					CIFile	fileNH(loadZ);
					CZone	zoneNH;
					zoneNH.serial(fileNH);
					fileNH.close();
					if (zoneNH.getZoneId() != _ZoneIds[i])
					{
						nlwarning ("Zone %s ID is wrong. Abort.", filenameNH.c_str());
						return;
					}
					landscapeNoHm.addZone(zoneNH);
				}
				else
				{
					useNoHmZones = false;
				}
			}

			_ZonePtrs.push_back(landscape.getZone(_ZoneIds[i]));
		}

		landscape.setNoiseMode(false);
		landscape.checkBinds();

		if (useNoHmZones)
		{
			landscapeNoHm.setNoiseMode(false);
			landscapeNoHm.checkBinds();
		}

		BestFittingBBox.setCenter(CVector::Null);
		BestFittingBBox.setHalfSize(CVector::Null);
		BestFittingBBoxSetuped= false;

		// Compute best fitting bbox
		for (i=0; i<_ZoneIds.size(); ++i)
		{
			if (_ZoneIds[i] == CentralZoneId)
			{
				if(_ZonePtrs[i]->getNumPatchs()>0)
				{
					BestFittingBBox = _ZonePtrs[i]->getZoneBB().getAABBox();
					BestFittingBBoxSetuped= true;
				}
			}
		}

		CAABBox	enlBBox = BestFittingBBox;
		enlBBox.setHalfSize(enlBBox.getHalfSize()+CVector(8.0f, 8.0f, 1000.0f));

		// Add neighbor patch
		for (i=0; i<_ZoneIds.size(); ++i)
		{
			if (_ZoneIds[i] == CentralZoneId)
			{
				for (j=0; (sint)j<_ZonePtrs[i]->getNumPatchs(); ++j)
				{
					landscape.excludePatchFromRefineAll(_ZoneIds[i], j, false);
					if (useNoHmZones)
						landscapeNoHm.excludePatchFromRefineAll(_ZoneIds[i], j, false);
				}
				if (Verbose)
					nlinfo(" - selected %d/%d patches for zone %d", _ZonePtrs[i]->getNumPatchs(), _ZonePtrs[i]->getNumPatchs(), _ZoneIds[i]);
			}
			else
			{
				uint	nump = 0;
				for (j=0; (sint)j<_ZonePtrs[i]->getNumPatchs(); ++j)
				{
					CAABBox	pbox = _ZonePtrs[i]->getPatch(j)->buildBBox();
					bool	inters = enlBBox.intersect(pbox);

					if (inters)
					{
						landscape.excludePatchFromRefineAll(_ZoneIds[i], j, false);
						if (useNoHmZones)
							landscapeNoHm.excludePatchFromRefineAll(_ZoneIds[i], j, false);
						++nump;
					}
					else
					{
						landscape.excludePatchFromRefineAll(_ZoneIds[i], j, true);
						if (useNoHmZones)
							landscapeNoHm.excludePatchFromRefineAll(_ZoneIds[i], j, true);
					}
				}
				if (Verbose)
					nlinfo(" - selected %d/%d patches for zone %d", nump, _ZonePtrs[i]->getNumPatchs(), _ZoneIds[i]);
			}
		}

		// tessellate the landscape, get the leaves (the tessellation faces), and convert them
		// into surf elements
		if (Verbose)
			nlinfo("Compute landscape tessellation");

		if (Verbose)
			nlinfo("   - tessellate landscape");

		if (useNoHmZones)
		{
			// Before tesselate, verify that the 2 landscape zones have at least the same binds!
			// Else there will be errors because of not the same tesselation
			checkSameLandscapeHmBinds(landscape, landscapeNoHm);
			
			// Tesselate
			landscapeNoHm.setThreshold(0.0f);
			landscapeNoHm.setTileMaxSubdivision(TessellateLevel);
			landscapeNoHm.refineAll(CVector::Null);
			landscapeNoHm.averageTesselationVertices();

			// get the faces
			vector<const CTessFace *>	leavesNoHm;
			landscapeNoHm.getTessellationLeaves(leavesNoHm);

			for (el=0; el<(sint)leavesNoHm.size(); ++el)
			{
				const CTessFace	*face = leavesNoHm[el];
				const CVector	*v[3];

				// get the vertices of the face
				v[0] = &(face->VBase->EndPos);
				v[1] = &(face->VLeft->EndPos);
				v[2] = &(face->VRight->EndPos);

				normals.push_back( ((*(v[1])-*(v[0])) ^ (*(v[2])-*(v[0]))).normed() );

				vectorCheck.push_back(*(v[0]));
				vectorCheck.push_back(*(v[1]));
				vectorCheck.push_back(*(v[2]));
			}
		}
	}

	// Build the lanscape with heightmap
	landscape.setThreshold(0.0f);
	landscape.setTileMaxSubdivision(TessellateLevel);
	landscape.refineAll(CVector::Null);
	landscape.averageTesselationVertices();

	vector<const CTessFace *>	leaves;
	landscape.getTessellationLeaves(leaves);
	if (Verbose)
	{
		if (useNoHmZones)
			nlinfo("      - used no height map zones");
		nlinfo("      - generated %d leaves", leaves.size());
	}

	// If don't use NoHm zones, build normals and vectorCheck directly from std landscape
	if (!useNoHmZones)
	{
		for (el=0; el<(sint)leaves.size(); ++el)
		{
			const CTessFace	*face = leaves[el];
			const CVector	*v[3];

			// get the vertices of the face
			v[0] = &(face->VBase->EndPos);
			v[1] = &(face->VLeft->EndPos);
			v[2] = &(face->VRight->EndPos);

			normals.push_back( ((*(v[1])-*(v[0])) ^ (*(v[2])-*(v[0]))).normed() );

			vectorCheck.push_back(*(v[0]));
			vectorCheck.push_back(*(v[1]));
			vectorCheck.push_back(*(v[2]));
		}
	}

	// check that there is the same number of faces from landscape with and without heightmap
	if (normals.size() != leaves.size())
	{
		nlwarning ("ERROR : The heightmaped landscape has not the same number of polygon than the nonheightmaped landscape: %d/%d.", 
			normals.size(), leaves.size());
		exit (0);
	}

	// generate a vector of vertices and of surf element
	CHashMap<const CVector *, uint32, CHashPtr<const CVector> >				vremap;
	CHashMap<const CVector *, uint32, CHashPtr<const CVector> >::iterator	vremapit;
	CHashMap<const CTessFace *, CSurfElement *, CHashPtr<const CTessFace> >	fremap;
	CHashMap<const CTessFace *, CSurfElement *, CHashPtr<const CTessFace> >::iterator	fremapit;
	_Vertices.clear();
	_Tessellation.resize(leaves.size());

	if (Verbose)
		nlinfo("   - make and remap surface elements");

	for (el=0; el<(sint)leaves.size(); ++el)
		fremap[leaves[el]] = &(_Tessellation[el]);

	uint	check = 0;

	float	dist, maxdist = 0.0f;

	for (el=0; el<(sint)leaves.size(); ++el)
	{
		const CTessFace	*face = leaves[el];
		const CVector	*v[3];

		CSurfElement	&element = _Tessellation[el];

		// setup zone id
		element.ZoneId = face->Patch->getZone()->getZoneId();

		// get the vertices of the face
		v[0] = &(face->VBase->EndPos);
		v[1] = &(face->VLeft->EndPos);
		v[2] = &(face->VRight->EndPos);

		{
			CVector	vcheck;

			vcheck = vectorCheck[check++] - *(v[0]);
			vcheck.z = 0;
			dist = vcheck.norm();
			if (dist > maxdist)	maxdist = dist;
			//nlassert(vcheck.norm() < 0.1f);

			vcheck = vectorCheck[check++] - *(v[1]);
			vcheck.z = 0;
			dist = vcheck.norm();
			if (dist > maxdist)	maxdist = dist;
			//nlassert(vcheck.norm() < 0.1f);

			vcheck = vectorCheck[check++] - *(v[2]);
			vcheck.z = 0;
			dist = vcheck.norm();
			if (dist > maxdist)	maxdist = dist;
			//nlassert(vcheck.norm() < 0.1f);
		}

		//element.Normal = ((*(v[1])-*(v[0])) ^ (*(v[2])-*(v[0]))).normed();
		element.Normal = normals[el];


		// search the vertices in the map
		for (i=0; i<3; ++i)
		{
			// if doesn't exist, create a new vertex
			if ((vremapit = vremap.find(v[i])) == vremap.end())
			{
				element.Tri[i] = (uint32)_Vertices.size();
				_Vertices.push_back(*(v[i]));
				vremap.insert(make_pair(v[i], element.Tri[i]));
			}
			// else use previous
			else
			{
				element.Tri[i] = vremapit->second;
			}
		}

		// setup the vertices pointer
		element.Vertices = &_Vertices;

		CTessFace		*edge[3];

		edge[0] = face->FBase;
		edge[1] = face->FRight;
		edge[2] = face->FLeft;

		for (i=0; i<3; ++i)
		{
			fremapit = fremap.find(edge[i]);
			element.EdgeLinks[i] = (fremapit != fremap.end() ? fremapit->second : NULL);
		}
	}

	for (el=0; el<(sint)_Tessellation.size(); ++el)
	{
		// add the element to the list of valid elements
		Elements.push_back(&(_Tessellation[el]));
	}

	landscape.clear();
}
Esempio n. 20
0
bool CExportNel::mirrorPhysiqueSelection(INode &node, TimeValue tvTime, const std::vector<uint> &vertIn, 
		float threshold)
{
	bool	ok;
	uint	i;

	// no vertices selected?
	if(vertIn.empty())
		return true;

	// **** Get all the skeleton node 
	std::vector<INode*>		skeletonNodes;
	INode	*skelRoot= getSkeletonRootBone(node);
	if(!skelRoot)
		return false;
	getObjectNodes(skeletonNodes, tvTime, skelRoot);


	// **** Build the Vector (world) part
	std::vector<CTempSkinVertex>	tempVertex;
	uint	vertCount;

	// Get a pointer on the object's node.
    ObjectState os = node.EvalWorldState(tvTime);
    Object *obj = os.obj;

	// Check if there is an object
	ok= false;
	if (obj)
	{		

		// Object can be converted in triObject ?
		if (obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) 
		{ 
			// Get a triobject from the node
			TriObject *tri = (TriObject*)obj->ConvertToType(tvTime, Class_ID(TRIOBJ_CLASS_ID, 0));
			
			if (tri)
			{
				// Note that the TriObject should only be deleted
				// if the pointer to it is not equal to the object
				// pointer that called ConvertToType()
				bool deleteIt=false;
				if (obj != tri) 
					deleteIt = true;

				// Get the node matrix. TODO: Matrix headhache?
				/*Matrix3 nodeMatrixMax;
				CMatrix nodeMatrix;
				getLocalMatrix (nodeMatrixMax, node, tvTime);
				convertMatrix (nodeMatrix, nodeMatrixMax);*/

				// retrive Position geometry
				vertCount= tri->NumPoints();
				tempVertex.resize(vertCount);
				for(uint i=0;i<vertCount;i++)
				{
					Point3 v= tri->GetPoint(i);
					tempVertex[i].Pos.set(v.x, v.y, v.z);
				}

				// Delete the triObject if we should...
				if (deleteIt)
					tri->MaybeAutoDelete();
				tri = NULL;

				// ok!
				ok= true;
			}
		}
	}
	if(!ok)
		return false;

	// no vertices? abort
	if(vertCount==0)
		return true;


	// **** Mark all Input vertices
	for(i=0;i<vertIn.size();i++)
	{
		nlassert(vertIn[i]<vertCount);
		tempVertex[vertIn[i]].Input= true;
	}


	// **** Build the output vertices
	std::vector<uint>	vertOut;
	vertOut.reserve(tempVertex.size());

	// Build the in bbox
	CAABBox		bbox;
	bbox.setCenter(tempVertex[vertIn[0]].Pos);
	for(i=0;i<vertIn.size();i++)
	{
		bbox.extend(tempVertex[vertIn[i]].Pos);
	}
	bbox.setHalfSize(bbox.getHalfSize()+CVector(threshold, threshold, threshold));

	// mirror in X
	CVector		vMin= bbox.getMin();
	CVector		vMax= bbox.getMax();
	vMin.x= -vMin.x;
	vMax.x= -vMax.x;
	std::swap(vMin.x, vMax.x);
	bbox.setMinMax(vMin, vMax);

	// get all out vertices in the mirrored bbox.
	for(i=0;i<tempVertex.size();i++)
	{
		if(bbox.include(tempVertex[i].Pos))
		{
			vertOut.push_back(i);
		}
	}


	// **** Build the skin information
	// Get the skin modifier
	Modifier* skin=getModifier (&node, PHYSIQUE_CLASS_ID);

	// Found it ?
	ok= false;
	if (skin)
	{
		// Get a com_skin2 interface
		IPhysiqueExport *physiqueInterface=(IPhysiqueExport *)skin->GetInterface (I_PHYINTERFACE);

		// Found com_skin2 ?
		if (physiqueInterface)
		{
			// Get local data
			IPhyContextExport *localData= physiqueInterface->GetContextInterface(&node);

			// Found ?
			if (localData)
			{
				// Use rigid export
				localData->ConvertToRigid (TRUE);

				// Allow blending
				localData->AllowBlending (TRUE);

				// Skinned
				ok=true;

				// TODO?
				nlassert(tempVertex.size()<=(uint)localData->GetNumberVertices());

				// For each vertex
				for (uint vert=0; vert<vertCount; vert++)
				{
					// Get a vertex interface
					IPhyVertexExport *vertexInterface= localData->GetVertexInterface (vert);

					// Check if it is a rigid vertex or a blended vertex
					IPhyRigidVertex			*rigidInterface=NULL;
					IPhyBlendedRigidVertex	*blendedInterface=NULL;
					int type=vertexInterface->GetVertexType ();
					if (type==RIGID_TYPE)
					{
						// this is a rigid vertex
						rigidInterface=(IPhyRigidVertex*)vertexInterface;
					}
					else
					{
						// It must be a blendable vertex
						nlassert (type==RIGID_BLENDED_TYPE);
						blendedInterface=(IPhyBlendedRigidVertex*)vertexInterface;
					}

					// Get bones count for this vertex
					uint boneCount;
					if (blendedInterface)
					{
						// If blenvertex, only one bone
						boneCount=blendedInterface->GetNumberNodes();
					}
					else
					{
						// If rigid vertex, only one bone
						boneCount=1;
					}
					if(boneCount>TEMP_MAX_WEIGHT)
						boneCount= TEMP_MAX_WEIGHT;

					// NB: if input 0, won't be mirrored
					tempVertex[vert].NumWeight= boneCount;
					for(uint bone=0;bone<boneCount;bone++)
					{
						if (blendedInterface)
						{
							tempVertex[vert].Bone[bone]= blendedInterface->GetNode(bone);
							nlassert(tempVertex[vert].Bone[bone]);
							tempVertex[vert].Weight[bone]= blendedInterface->GetWeight(bone);
						}
						else
						{
							tempVertex[vert].Bone[bone]= rigidInterface->GetNode();
							tempVertex[vert].Weight[bone]= 1;
						}
					}

					// Release vertex interfaces
					localData->ReleaseVertexInterface (vertexInterface);
				}

			}

			// release context interface
			physiqueInterface->ReleaseContextInterface(localData);
		}

		// Release the interface
		skin->ReleaseInterface (I_PHYINTERFACE, physiqueInterface);
	}
	if(!ok)
		return false;


	// **** Real Algo stuff:
	// For all vertices wanted to be mirrored
	std::vector<CSortVertex>	sortVert;
	sortVert.reserve(tempVertex.size());
	for(i=0;i<vertIn.size();i++)
	{
		CTempSkinVertex		&svIn= tempVertex[vertIn[i]];
		// if it still has no bones set, skip
		if(svIn.NumWeight==0)
			continue;

		// mirror vert to test
		CVector		vertTest= svIn.Pos;
		vertTest.x*= -1;

		// get the best vertex
		sortVert.clear();

		// Search for all output vertices if ones match
		for(uint j=0;j<vertOut.size();j++)
		{
			uint	dstIdx= vertOut[j];
			nlassert(dstIdx<tempVertex.size());
			CTempSkinVertex	&skinv= tempVertex[dstIdx];
			// take only if not an input, and if not already mirrored
			if(!skinv.Input && !skinv.Mirrored)
			{
				CSortVertex		sortv;
				sortv.Index= dstIdx;
				sortv.SqrDist= (skinv.Pos - vertTest).sqrnorm();
				// Finally, take it only if sufficiently near
				if(sortv.SqrDist <= threshold*threshold)
					sortVert.push_back(sortv);
			}
		}

		// if some found.
		if(!sortVert.empty())
		{
			// sort array.
			std::sort(sortVert.begin(), sortVert.end());

			// take the first, mirror setup
			uint	dstIdx= sortVert[0].Index;
			tempVertex[dstIdx].NumWeight= svIn.NumWeight;
			for(uint k=0;k<svIn.NumWeight;k++)
			{
				tempVertex[dstIdx].Weight[k]= svIn.Weight[k];
				tempVertex[dstIdx].Bone[k]= getMirrorBone( skeletonNodes, svIn.Bone[k] );
			}

			// mark as mirrored!
			tempVertex[dstIdx].Mirrored= true;
		}
	}


	// **** Write the result to the skin.
	ok= false;
	if (skin)
	{
		// Get a com_skin2 interface
		IPhysiqueImport *physiqueInterface=(IPhysiqueImport *)skin->GetInterface (I_PHYIMPORT);

		// Found com_skin2 ?
		if (physiqueInterface)
		{
			// Get local data
			IPhyContextImport *localData= physiqueInterface->GetContextInterface(&node);

			// TODO?
			nlassert(tempVertex.size()<=(uint)localData->GetNumberVertices());

			// Found ?
			if (localData)
			{
				// Skinned
				ok=true;
				
				for(uint i=0;i<tempVertex.size();i++)
				{
					CTempSkinVertex		&sv= tempVertex[i];

					// if its a mirrored output vertex
					if(sv.Mirrored)
					{
						IPhyBlendedRigidVertexImport	*blendedInterface= NULL;
						blendedInterface= (IPhyBlendedRigidVertexImport*)localData->SetVertexInterface(i, RIGID_BLENDED_TYPE);

						if(blendedInterface)
						{
							// set the vertex data
							for(uint bone=0;bone<sv.NumWeight;bone++)
							{
								blendedInterface->SetWeightedNode(sv.Bone[bone], sv.Weight[bone], bone==0);
							}

							// UI bonus: lock it
							blendedInterface->LockVertex(TRUE);

							// release
							localData->ReleaseVertexInterface(blendedInterface);
						}
					}
				}
			}

			// release
			physiqueInterface->ReleaseContextInterface(localData);
		}

		// release
		skin->ReleaseInterface(I_PHYIMPORT, physiqueInterface);
	}


	return ok;
}
	bool	operator () (const CAABBox &a, const CAABBox &b) const
	{
		return a.getCenter().z < b.getCenter().z;
	}
void	NLPACS::CZoneTessellation::compile()
{
	sint	el;
	uint	i;

	CAABBox	tbox = computeBBox();

	bool	HasInvertedUnderWater = false;

	// setup cliffs
	for (el=0; el<(sint)Elements.size(); ++el)
	{
		CSurfElement	&element = *(Elements[el]);

		// a cliff ?
		if (element.Normal.z < 0.0)
		{
			CVector		&v0 = _Vertices[element.Tri[0]],
						&v1 = _Vertices[element.Tri[1]],
						&v2 = _Vertices[element.Tri[2]];

			uint8		bits0 = PrimChecker.get((uint)v0.x, (uint)v0.y);
			uint8		bits1 = PrimChecker.get((uint)v1.x, (uint)v1.y);
			uint8		bits2 = PrimChecker.get((uint)v2.x, (uint)v2.y);

			bool		w0 = ((bits0&CPrimChecker::Water) != 0);
			bool		w1 = ((bits1&CPrimChecker::Water) != 0);
			bool		w2 = ((bits2&CPrimChecker::Water) != 0);

			if ((bits0 & CPrimChecker::Water)!=0 || (bits1 & CPrimChecker::Water)!=0 || (bits2 & CPrimChecker::Water)!=0)
			{
				uint		ws = 0;

				uint16		ws0 = PrimChecker.index((uint)v0.x, (uint)v0.y);
				uint16		ws1 = PrimChecker.index((uint)v1.x, (uint)v1.y);
				uint16		ws2 = PrimChecker.index((uint)v2.x, (uint)v2.y);

				if ((w0 && w1 && ws0 == ws1) || (w0 && w2 && ws0 == ws2))
					ws = ws0;
				else if (w1 && w2 && ws1 == ws2)
					ws = ws1;
				else if (w0)
					ws = ws0;
				else if (w1)
					ws = ws1;
				else if (w2)
					ws = ws2;

				float		minz = std::min(_Vertices[element.Tri[0]].z, 
								   std::min(_Vertices[element.Tri[1]].z,
											_Vertices[element.Tri[2]].z));

				bool		exists;
				float		wh = PrimChecker.waterHeight(ws, exists)+WaterThreshold;

				// 
				if (minz <= wh)
				{
					CPolygon	p(v0, v1, v2);
					PrimChecker.renderBits(p, CPrimChecker::Cliff);

					HasInvertedUnderWater = true;
				}
			}
		}
	}

	if (HasInvertedUnderWater)
	{
		nlwarning("zone '%s' has reversed landscape under water", (getZoneNameById((uint16)CentralZoneId)+ZoneExt).c_str());
	}


	// compute elements features
	if (Verbose)
		nlinfo("compute elements quantas");
	for (el=0; el<(sint)Elements.size(); ++el)
	{
		CSurfElement	&element = *(Elements[el]);

		element.ElemId = el;
		element.computeQuantas(this);
	}

	if (ReduceSurfaces)
	{
		// optimizes the number of generated segments
		// it also smoothes a bit the surface border
		// it seems that 3 consecutive passes are optimal to reduce
		// nasty granularity
		if (Verbose)
			nlinfo("reduce surfaces");
		uint	i;
		sint	p;

		for (i=0; i<3; ++i)
		{
			for (p=0; p<(sint)Elements.size(); ++p)
			{
				CSurfElement	&e = *(Elements[p]);
				CSurfElement	&e0 = *e.EdgeLinks[0],
								&e1 = *e.EdgeLinks[1],
								&e2 = *e.EdgeLinks[2];

				if (e.IsMergable && &e0 != NULL && &e1 != NULL && &e2 != NULL &&
					e.ZoneId == e0.ZoneId &&
					e.ZoneId == e1.ZoneId &&
					e.ZoneId == e2.ZoneId &&
					!e.ForceInvalid)
				{
					// Strong optimization
					// merge the element quantas to the neighbors' quantas which are the most numerous
					// quantas are evaluated individually
					if (e0.IsValid && e1.IsValid)						e.IsValid = true;
					if (e1.IsValid && e2.IsValid)						e.IsValid = true;
					if (e0.IsValid && e2.IsValid)						e.IsValid = true;

					if (e0.QuantHeight == e1.QuantHeight)				e.QuantHeight = e0.QuantHeight;
					if (e1.QuantHeight == e2.QuantHeight)				e.QuantHeight = e1.QuantHeight;
					if (e0.QuantHeight == e2.QuantHeight)				e.QuantHeight = e2.QuantHeight;

					if (e0.IsValid && e1.IsValid && e0.WaterShape == e1.WaterShape && e0.IsUnderWater == e1.IsUnderWater)
					{
						e.WaterShape = e0.WaterShape;
						e.IsUnderWater = e0.IsUnderWater;
					}
					if (e1.IsValid && e2.IsValid && e1.WaterShape == e2.WaterShape && e1.IsUnderWater == e2.IsUnderWater)
					{
						e.WaterShape = e1.WaterShape;
						e.IsUnderWater = e1.IsUnderWater;
					}
					if (e0.IsValid && e2.IsValid && e0.WaterShape == e2.WaterShape && e0.IsUnderWater == e2.IsUnderWater)
					{
						e.WaterShape = e2.WaterShape;
						e.IsUnderWater = e2.IsUnderWater;
					}
				}
			}
		}

		for (p=0; p<(sint)Elements.size(); ++p)
		{
			CSurfElement	&e = *(Elements[p]);
			CSurfElement	&e0 = *e.EdgeLinks[0],
							&e1 = *e.EdgeLinks[1],
							&e2 = *e.EdgeLinks[2];

			if (&e != NULL && &e0 != NULL && &e1 != NULL && &e2 != NULL &&
				e.IsValid && e0.IsValid && e1.IsValid && e2.IsValid &&
				!e.IsUnderWater && e0.IsUnderWater && e1.IsUnderWater && e2.IsUnderWater)
			{
				nlwarning("isolated submerged element '%d' !", p);
			}
		}
	}

	// translates vertices to the local axis
	sint64	vx, vy, vz, tx, ty, tz;
	tx = float2Fixed(Translation.x);
	ty = float2Fixed(Translation.y);
	tz = float2Fixed(Translation.z);

	uint	p;
	for (i=0; i<_Vertices.size(); ++i)
	{
		vx = float2Fixed(_Vertices[i].x) + tx;
		vy = float2Fixed(_Vertices[i].y) + ty;
		vz = float2Fixed(_Vertices[i].z) + tz;
		_Vertices[i] = CVector(fixed2Float(vx), fixed2Float(vy), fixed2Float(vz));
	}

	if(BestFittingBBoxSetuped)
		BestFittingBBox.setCenter(BestFittingBBox.getCenter()+Translation);


	//
	//if (false)
	{
		//
		// first pass of flood fill
		// allow detecting landscape irregularities
		//

		if (Verbose)
			nlinfo("build and flood fill surfaces -- pass 1");
		uint32	surfId = 0; // + (ZoneId<<16);

		for (p=0; p<Elements.size(); ++p)
		{
			if (Elements[p]->SurfaceId == UnaffectedSurfaceId)
			{
				Surfaces.push_back(CComputableSurface());
				CComputableSurface	&surf = Surfaces.back();

				surf.BorderKeeper = &Borders;
				surf.floodFill(Elements[p], surfId++, CSurfElemCompareSimple(), this);
				surf.BBox = BestFittingBBox;

				bool	force = false;

				if (surf.Area < 30.0f && surf.Elements.size() > 0)
				{
					uint		i;
					CAABBox		aabbox;

					aabbox.setCenter((*surf.Elements[0]->Vertices)[surf.Elements[0]->Tri[0]]);

					for (i=0; i<surf.Elements.size(); ++i)
					{
						aabbox.extend((*surf.Elements[i]->Vertices)[surf.Elements[i]->Tri[0]]);
						aabbox.extend((*surf.Elements[i]->Vertices)[surf.Elements[i]->Tri[1]]);
						aabbox.extend((*surf.Elements[i]->Vertices)[surf.Elements[i]->Tri[2]]);
					}

					// swap all suface elements validity
					if (!surf.Elements[0]->ForceInvalid && aabbox.getHalfSize().z < 1.5f)
					{
						for (i=0; i<surf.Elements.size(); ++i)
						{
							surf.Elements[i]->IsValid = !surf.Elements[i]->IsValid;
						}
						if (Verbose)
							nlinfo("Reverted surface %d (%d elements, water=%d)", surfId-1, surf.Elements.size(), (surf.IsUnderWater ? 1 : 0));
					}
				}
			}
		}

		Surfaces.clear();
		ExtSurfaces.clear();
	}

	vector<CSurfElement*>	elDup;
	for (el=0; el<(sint)Elements.size(); ++el)
		if (Elements[el]->IsValid)
			elDup.push_back(Elements[el]);
	Elements = elDup;
	elDup.clear();

	for (el=0; el<(sint)Elements.size(); ++el)
	{
		CSurfElement	&element = *(Elements[el]);
		element.SurfaceId = UnaffectedSurfaceId;
		uint	i;
		for (i=0; i<3; ++i)
			if (element.EdgeLinks[i] != NULL && !element.EdgeLinks[i]->IsValid)
				element.EdgeLinks[i] = NULL;
	}

	//
	{
		if (Verbose)
			nlinfo("build and flood fill surfaces");
		uint32	surfId = 0; // + (ZoneId<<16);
		uint	totalSurf = 0;
		sint32	extSurf = -1024;

		for (p=0; p<Elements.size(); ++p)
		{
			if (Elements[p]->SurfaceId == UnaffectedSurfaceId)
			{
				bool	elInCentral = (Elements[p]->ZoneId == CentralZoneId);

				++totalSurf;
				sint32	thisSurfId = (elInCentral) ? surfId++ : extSurf--;
				if (elInCentral)
					Surfaces.push_back(CComputableSurface());
				else
					ExtSurfaces.push_back(CComputableSurface());

				CComputableSurface	&surf = (elInCentral) ? Surfaces.back() : ExtSurfaces.back();

				surf.BorderKeeper = &Borders;
				surf.floodFill(Elements[p], thisSurfId, CSurfElemCompareNormal(), this);
				surf.BBox = BestFittingBBox;
			}
		}

		if (Verbose)
		{
			nlinfo("%d surfaces generated", totalSurf);

			for (p=0; p<Surfaces.size(); ++p)
			{
				nlinfo("surf %d: %d elements", p, Surfaces[p].Elements.size());

				if (Surfaces[p].Elements.size() == 1)
				{
					nlinfo("elm: %d", Surfaces[p].Elements[0]->ElemId);
				}
			}
		}
	}

	// flag vertices that are pointed by more than 2 surfaces
	VerticesFlags.resize(_Vertices.size(), 0);

	for (p=0; p<Elements.size(); ++p)
	{
		CSurfElement	*elem = Elements[p];

		sint32		s = elem->SurfaceId;
		sint32		s0 = (elem->EdgeLinks[0] != NULL ? elem->EdgeLinks[0]->SurfaceId : UnaffectedSurfaceId);
		sint32		s1 = (elem->EdgeLinks[1] != NULL ? elem->EdgeLinks[1]->SurfaceId : UnaffectedSurfaceId);
		sint32		s2 = (elem->EdgeLinks[2] != NULL ? elem->EdgeLinks[2]->SurfaceId : UnaffectedSurfaceId);

		if (s != s0 && s != s1 && s0 != s1)
		{
			VerticesFlags[elem->Tri[2]] = 1;
		}

		if (s != s1 && s != s2 && s1 != s2)
		{
			VerticesFlags[elem->Tri[0]] = 1;
		}

		if (s != s2 && s != s0 && s2 != s0)
		{
			VerticesFlags[elem->Tri[1]] = 1;
		}
	}
}
Esempio n. 23
0
// ***************************************************************************
void			IShape::getAABBox(CAABBox &bbox) const
{
	bbox.setCenter(CVector::Null);
	bbox.setHalfSize(CVector::Null);
}
Esempio n. 24
0
void UpdatePrimitives ()
{
	// Get the tools window
	CMainFrame *mainWnd = getMainFrame ();
	if (mainWnd)
	{
		CToolsLogic *toolWnd = dynamic_cast<CToolsLogic*>(getMainFrame ()->m_wndSplitter.GetPane(0,1));

		// Sort the list
		static vector<CDatabaseLocatorPointer>	toSort;
		toSort.clear ();

		CWorldEditorDoc *doc = getDocument ();
		std::list<NLLIGO::IPrimitive*>::iterator ite = ModifiedPrimitive.begin ();
		while (ite != ModifiedPrimitive.end ())
		{
			CDatabaseLocatorPointer locator;
			doc->getLocator (locator, *ite);
			toSort.push_back (locator);
			ite++;
		}
		sort (toSort.begin (), toSort.end ());

		// For each modified primitive 
		sint i;
		sint count = (sint)toSort.size ();
		for (i=count-1; i>=0; i--)
		{
			CDatabaseLocatorPointer locator;
			doc->getLocator (locator, toSort[i].Primitive);
			IPrimitiveEditor *primitiveEditor = getPrimitiveEditor (const_cast<IPrimitive*>(toSort[i].Primitive));

			// Logic tree structure modified ?
			if (primitiveEditor->_Channels & LogicTreeStruct)
			{
				// Remove from the tree
				primitiveEditor->removeFromLogicTree ();
			}
		}

		// Selection is changed ?
		bool selectionChanged = false;

		// For each modified primitive 
		for (i=0; i<count; i++)
		{
			const IPrimitive *primitive = toSort[i].Primitive;
			CDatabaseLocatorPointer locator;
			doc->getLocator (locator, primitive);
			IPrimitiveEditor *primitiveEditor = getPrimitiveEditor (const_cast<IPrimitive*>(primitive));

			// Quad grid ?
			if (primitiveEditor->_Channels & QuadTree)
			{
				// Remove from the container
				primitiveEditor->removeFromQuadGrid ();

				// Num points
				uint pointCount = (primitive)->getNumVector ();
				if (pointCount > 0)
				{
					// Point pointer
					const CPrimVector *points = (primitive)->getPrimVector ();

					// BBox
					CAABBox	bbox;
					bbox.setCenter (points[0]);

					// Extend the bbox
					uint j;
					for (j=1; j<pointCount; j++)
					{
						bbox.extend (points[j]);
					}

					// Insert in the quadtree
					primitiveEditor->_QuadIterator = PrimitiveQuadGrid.insert (bbox.getMin (), bbox.getMax (), const_cast<IPrimitive*> (primitive));

					// Get the linked primitives
					const IPrimitive* linkedPrimitive = theApp.Config.getLinkedPrimitive (*primitive);

					// Is this primitive linked with another one ?
					if (linkedPrimitive)
					{
						IPrimitiveEditor *primitiveEditorLinked = getPrimitiveEditor (const_cast<IPrimitive*>(linkedPrimitive));
						if (linkedPrimitive->getNumVector () > 0)
						{
							bbox.setCenter (points[0]);
							bbox.extend (linkedPrimitive->getPrimVector ()[0]);

							// Insert in the quadtree
							primitiveEditor->_QuadIteratorLink = PrimitiveQuadGrid.insert (bbox.getMin (), bbox.getMax (), CQuadGridEntry 
								(const_cast<IPrimitive*> (primitive), const_cast<IPrimitive*> (linkedPrimitive)));
						}
					}
				}

				// Validate
				primitiveEditor->_Channels &= ~QuadTree;
			}

			// Logic tree structure ?
			if (primitiveEditor->_Channels & LogicTreeStruct)
			{
				// Add the primitive
				AddPrimitivesLogicTree (locator, primitiveEditor, toolWnd);

				// The flag is validated by AddPrimitivesLogicTree
			}

			// Logic tree parameters ?
			if (primitiveEditor->_Channels & LogicTreeParam)
			{
				// Update tree item parameters
				if (toolWnd)
					toolWnd->updatePrimitive (primitiveEditor->_TreeItem, locator);

				// Validate
				primitiveEditor->_Channels &= ~LogicTreeParam;
			}

			// Selection ?
			if (primitiveEditor->_Channels & _SelectionSelectState)
			{
				// Update the selection
				UpdatePrimitiveSelection (primitiveEditor, locator, selectionChanged);

				// Validate
				primitiveEditor->_Channels &= ~_SelectionSelectState;
			}

			// Remove from the modified list
			nlassert (primitiveEditor->_Channels == 0);
			ModifiedPrimitive.erase (primitiveEditor->_ModifiedIterator);
			primitiveEditor->_ModifiedIterator = ModifiedPrimitive.end ();
		}

		/*// Change dialog selection ?
		if (selectionChanged)
		{
			if ( pDlg )
				pDlg->changeSelection (Selection);
		}
*/
		nlassert (ModifiedPrimitive.size ()==0);
	}
}
Esempio n. 25
0
void	computeRetriever(CCollisionMeshBuild &cmb, CLocalRetriever &lr, CVector &translation, bool useCmbTrivialTranslation)
{
	// set the retriever
	lr.setType(CLocalRetriever::Interior);

	// if should use the own cmb bbox, then compute it
	if (useCmbTrivialTranslation)
	{
		translation = cmb.computeTrivialTranslation();
		// snap the translation vector to a meter wide grid
		translation.x = (float)ceil(translation.x);
		translation.y = (float)ceil(translation.y);
		translation.z = 0.0f;
	}

	uint	i, j;

	for (i=0; i<cmb.Faces.size(); ++i)
	{
		CVector		normal = ((cmb.Vertices[cmb.Faces[i].V[1]]-cmb.Vertices[cmb.Faces[i].V[0]])^(cmb.Vertices[cmb.Faces[i].V[2]]-cmb.Vertices[cmb.Faces[i].V[0]])).normed();

		if (normal.z < 0.0f)
		{
			nlwarning("Face %d in cmb (%s) has negative normal! -- face is flipped", i, cmb.Faces[i].Surface == CCollisionFace::InteriorSurfaceFirst ? "interior" : "exterior");
/*
			std::swap(cmb.Faces[i].V[1], cmb.Faces[i].V[2]);
			std::swap(cmb.Faces[i].Visibility[1], cmb.Faces[i].Visibility[2]);
*/
		}
	}

	// first link faces
/*
	linkMesh(cmb, false);
	linkMesh(cmb, true);
*/
	vector<string>	errors;
	
	cmb.link(false, errors);
	cmb.link(true, errors);

	if (!errors.empty())
	{
		nlwarning("Edge issues reported !!");
		uint	i;
		for (i=0; i<errors.size(); ++i)
			nlwarning("%s", errors[i].c_str());
		nlerror("Can't continue.");
	}
	
	// translate the meshbuild to the local axis
	cmb.translate(translation);

	// find the exterior mesh border
	CExteriorMesh	extMesh;
	buildExteriorMesh(cmb, extMesh);
	lr.setExteriorMesh(extMesh);

	// build the surfaces in the local retriever
	buildSurfaces(cmb, lr);

	// create the snapping faces and vertices
	// after the build surfaces because the InternalSurfaceId is filled within buildSurfaces()...
	buildSnapping(cmb, lr);

	//
	lr.computeLoopsAndTips();

	lr.findBorderChains();
	lr.updateChainIds();
	lr.computeTopologies();

	lr.unify();

	lr.computeCollisionChainQuad();
/*
	//
	for (i=0; i<lr.getSurfaces().size(); ++i)
		lr.dumpSurface(i);
*/
	//
	linkExteriorToInterior(lr);

	// compute the bbox of the retriever
	CAABBox	bbox;
	bool	first = true;

	for (i=0; i<extMesh.getEdges().size(); ++i)
		if (!first)
			bbox.extend(extMesh.getEdge(i).Start);
		else
			bbox.setCenter(extMesh.getEdge(i).Start), first=false;

	for (i=0; i<lr.getOrderedChains().size(); ++i)
		for (j=0; j<lr.getOrderedChain(i).getVertices().size(); ++j)
			if (!first)
				bbox.extend(lr.getOrderedChain(i)[j].unpack3f());
			else
				bbox.setCenter(lr.getOrderedChain(i)[j].unpack3f()), first=false;

	CVector	bboxhs = bbox.getHalfSize();
	bboxhs.z = 10000.0f;
	bbox.setHalfSize(bboxhs);

	lr.setBBox(bbox);
}
/**  Check a zone and report the total number of errors
  */
static uint CheckZone(std::string middleZoneFile, float weldThreshold, float middleEdgeWeldThreshold)
{
	uint numErrors = 0;
	uint k, l, m, n, p, q;	// some loop counters	
	// This avoid reporting errors twice (for readability)
	std::set<CPatchIdentPair> errorPairs;

	////////////////////////////
	// Load the zones around  //
	////////////////////////////

		std::auto_ptr<CZone>		zones[9];
		std::string					zoneNames[9];
		CZoneInfo					zoneInfos[9];				
		uint16  xPos, yPos;
		const sint16 posOffs[][2] = { {0, 0}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1} };

		std::string middleZoneName = CFile::getFilenameWithoutExtension(middleZoneFile);
		::getZoneCoordByName(middleZoneName.c_str(), xPos, yPos);
		try
		{
			std::string ext = CFile::getExtension(middleZoneFile);
			zones[0].reset(::LoadZone(xPos, yPos, ext.empty() ? "" : "." + ext));
			if (zones[0].get() == NULL)
			{
				nlwarning("Can't load zone  %s", middleZoneName.c_str());
				return 0;
			}
			for (uint k = 1; k < 9; ++k)
			{
				zones[k].reset(::LoadZone(xPos + posOffs[k][0], yPos + posOffs[k][1], ext.empty() ? "" : "." + ext));
			}
		}
		catch (NLMISC::Exception &e)
		{
			nlinfo("Zones loading failed : %d", e.what());
			return 0;
		}
	
	///////////////////////////////
	// retrieve datas from zones //
	///////////////////////////////

		for (k = 0; k < 9; ++k)
		{
			::getZoneNameByCoord(xPos + posOffs[k][0], yPos + posOffs[k][1], zoneNames[k]);			
			if (zones[k].get() != NULL) zones[k]->retrieve(zoneInfos[k]);
		}	

		// fill the quad grid
		CAABBox zoneBBox = zones[0]->getZoneBB().getAABBox();
		float zoneSize = 2.f * weldThreshold + std::max(zoneBBox.getMax().x - zoneBBox.getMin().x,
														 zoneBBox.getMax().y - zoneBBox.getMin().y);
		TPVQuadGrid qg;
		const uint numQGElt = 128;
		qg.create(numQGElt, zoneSize / numQGElt);

		// insert vertices in quadgrid
		for (k = 0; k < 9; ++k)
		{		
			for (l = 0; l < zoneInfos[k].Patchs.size(); ++l)
			{
				CPatchInfo &patch = zoneInfos[k].Patchs[l];
				// for each base vertex of the patch
				for (m = 0; m < 4; ++m)
				{
					CVector &pos = patch.Patch.Vertices[m];
					CBSphere s(pos, weldThreshold);
					if (zoneBBox.intersect(s)) // does this vertex and its zone of influence intersect the bbox ?
					{
						CVector half(weldThreshold, weldThreshold, weldThreshold);
						// yes, insert it in the tree
						qg.insert(pos - half, pos + half, CPatchVertexInfo(k, l, m, pos));
					}			
				}
			}
		}

	////////////////////////////////////////////////
	// check wether each patch is correctly bound //
	////////////////////////////////////////////////

	for (l = 0; l < zoneInfos[0].Patchs.size(); ++l)
	{	
		CPatchInfo &patch = zoneInfos[0].Patchs[l];
		// deals with each border
		for (m = 0; m < 4; ++m)
		{			
			// if this border is said to be bound, no need to test..
			if (patch.BindEdges[m].NPatchs == 0)
			{
				// maps from an index to  a (s, t) couple
				static const float indexToST[][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};

				// index of this border vertices
				const uint vIndex[]  = { m, (m + 1) & 0x03 };

				bool errorFound = false;

				static TPVVect verts[2];

				// Get vertices from other patch that could be welded with this patch boder's vertices.
				for (q = 0; q < 2; ++q)
				{
					//nlinfo("pos = %f, %f, %f", patch.Patch.Vertices[vIndex[q]].x, patch.Patch.Vertices[vIndex[q]].y, patch.Patch.Vertices[vIndex[q]].z);
					::GetCandidateVertices(patch.Patch.Vertices[vIndex[q]], qg, verts[q], l, 0, weldThreshold);
				}

									
				///////////////////////////
				// 1 - 1 connectivity ?  //
				///////////////////////////	
				// If there is a patch that is present in the 2 lists, then this is a 1-1 error
				for (n = 0; n < verts[0].size() && !errorFound; ++n)
				{
					for (p = 0; p < verts[1].size() && !errorFound; ++p)
					{
						if (verts[0][n]->ZoneIndex == verts[1][p]->ZoneIndex
							&& verts[0][n]->PatchIndex == verts[1][p]->PatchIndex)
						{
							CPatchIdent pi1(0, l);
							CPatchIdent pi2(verts[0][n]->ZoneIndex, verts[0][n]->PatchIndex);
							CPatchIdentPair errPair = std::make_pair(pi1, pi2);
							//
							if (std::find(errorPairs.begin(), errorPairs.end(), errPair) == errorPairs.end()) // error already displayed ?
							{									
								nlinfo("**** Patch %d of zone %s has 1 - 1 connectivity error, try binding it with patch %d of zone %s",
										l + 1, middleZoneName.c_str(), verts[0][n]->PatchIndex + 1, zoneNames[verts[0][n]->ZoneIndex].c_str());										
								errorPairs.insert(std::make_pair(pi2, pi1));
								++numErrors;
							}
							errorFound = true;
						}
					}
				}
				if (errorFound) continue;

				//////////////////////////
				// 1 - 2 connectivity ? //
				//////////////////////////
			
				// get the position at the middle of that border
				CVector middlePos = patch.Patch.eval( 0.5f * (indexToST[vIndex[0]][0] + indexToST[vIndex[1]][0]),
													  0.5f * (indexToST[vIndex[0]][1] + indexToST[vIndex[1]][1]) );						

				// for each vertex of this border
				for (q = 0; q < 2 && !errorFound; ++q)
				{
					for (n = 0; n < verts[q].size() && !errorFound; ++n)
					{
						const CPatchVertexInfo &pv = *(verts[q][n]);
						// ref to the patch that share a vertex with this one
						const CBezierPatch &bPatch = zoneInfos[pv.ZoneIndex].Patchs[pv.PatchIndex].Patch;
						sint vertIndex = ::GetWeldableVertex(bPatch, pv.Pos, weldThreshold);
						nlassert(vertIndex != -1); // should found one..
						// Follow this patch edge and see if the next / previous vertex could be welded with the middle
						const CVector &nextVertPos = bPatch.Vertices[(vertIndex +  1) & 0x03];
						const CVector &prevVertPos = bPatch.Vertices[(vertIndex -  1) & 0x03];
						if (::CanWeld(nextVertPos, middlePos, middleEdgeWeldThreshold)
							|| ::CanWeld(prevVertPos, middlePos, middleEdgeWeldThreshold)
						   )
						{
							CPatchIdent pi1(0, l);
							CPatchIdent pi2(pv.ZoneIndex, pv.PatchIndex);
							CPatchIdentPair errPair = std::make_pair(pi1, pi2);
							//
							if (std::find(errorPairs.begin(), errorPairs.end(), errPair) == errorPairs.end()) // error already displayed ?
							{									
								nlinfo("**** Patch %d of zone %s has 1 - 2 connectivity error, try binding it with patch %d of zone %s",
										l + 1, middleZoneName.c_str(), pv.PatchIndex + 1, zoneNames[pv.ZoneIndex].c_str());										
								errorPairs.insert(std::make_pair(pi2, pi1));
								++numErrors;										
							}

							errorFound = true;
							break;
						}		
					}
				}
				if (errorFound) continue;						
					
				//////////////////////////
				// 1 - 4 connectivity ? //
				//////////////////////////
				
				// compute points along the border.
				CVector borderPos[5];
				float lambda = 0.f;
				for (n = 0; n < 5; ++n)
				{
					borderPos[n] = patch.Patch.eval((1.f - lambda) * indexToST[vIndex[0]][0] + lambda * indexToST[vIndex[1]][0],
													(1.f - lambda) * indexToST[vIndex[0]][1] + lambda * indexToST[vIndex[1]][1]);
					lambda += 0.25f;
				}						
				
				// Try to find a patch that shares 2 consecutives vertices
				for (k = 0; k < 4 && !errorFound; ++k)
				{
					::GetCandidateVertices(borderPos[k], qg, verts[0], l, 0, middleEdgeWeldThreshold); 
					for (p = 0; p < verts[0].size() && !errorFound; ++p)
					{
						const CPatchVertexInfo &pv = *(verts[0][p]);
						// ref to the patch that share a vertex with this one
						const CBezierPatch &bPatch = zoneInfos[pv.ZoneIndex].Patchs[pv.PatchIndex].Patch;
						sint vertIndex = ::GetWeldableVertex(bPatch, pv.Pos, weldThreshold);
						nlassert(vertIndex != -1); // should found one..
						// Follow this patch edge and see if the next/ previous  vertex could be welded with the next point
						const CVector &nextVertPos = bPatch.Vertices[(vertIndex +  1) & 0x03];
						const CVector &prevVertPos = bPatch.Vertices[(vertIndex -  1) & 0x03];

						if (::CanWeld(nextVertPos, borderPos[k + 1], middleEdgeWeldThreshold)
							|| 	::CanWeld(prevVertPos, borderPos[k + 1], middleEdgeWeldThreshold)
						   )
						{
							CPatchIdent pi1(0, l);
							CPatchIdent pi2(pv.ZoneIndex, pv.PatchIndex);
							CPatchIdentPair errPair = std::make_pair(pi1, pi2);
							//
							if (std::find(errorPairs.begin(), errorPairs.end(), errPair) == errorPairs.end()) // error already displayed ?
							{									
								nlinfo("**** Patch %d of zone %s has 1 - 4 connectivity error, try binding it with patch %d of zone %s",
									   l + 1, middleZoneName.c_str(), pv.PatchIndex + 1, zoneNames[pv.ZoneIndex].c_str());										
								++numErrors;
								errorPairs.insert(std::make_pair(pi2, pi1));
							}
							errorFound = true;
						}
					}
				}											
			}
		}
	}
	////////////////////////////////
	////////////////////////////////
	if (numErrors != 0)
	{
		nlinfo("%d errors found", numErrors);
	}
	return numErrors;
}