void NifImporter::SetNormals(Mesh& mesh, const vector<Niflib::Triangle>& tris, const vector<Niflib::Vector3>& n)
{
	mesh.checkNormals(TRUE);
	if (n.size() > 0)
	{
		bool needNormals = false;
		for (unsigned int i=0; i<n.size(); i++){
			Vector3 v = n[i];
			Point3 norm(v.x, v.y, v.z);
			if (norm != mesh.getNormal(i)) {
				needNormals = true;
				break;
			}
		}
		if (needNormals)
		{
#if VERSION_3DSMAX > ((5000<<16)+(15<<8)+0) // Version 5
			mesh.SpecifyNormals();
			MeshNormalSpec *specNorms = mesh.GetSpecifiedNormals ();
			if (NULL != specNorms)
			{
				specNorms->ClearAndFree();
				specNorms->SetNumFaces(tris.size());
				specNorms->SetNumNormals(n.size());

				Point3* norms = specNorms->GetNormalArray();
				for (unsigned int i=0; i<n.size(); i++){
					Vector3 v = n[i];
					norms[i] = Point3(v.x, v.y, v.z);
				}
				MeshNormalFace* pFaces = specNorms->GetFaceArray();
				for (unsigned int i=0; i<tris.size(); i++){
					const Triangle& tri = tris[i];
					pFaces[i].SpecifyNormalID(0, tri.v1);
					pFaces[i].SpecifyNormalID(1, tri.v2);
					pFaces[i].SpecifyNormalID(2, tri.v3);
				}
#if VERSION_3DSMAX > ((7000<<16)+(15<<8)+0) // Version 7+
				specNorms->SetAllExplicit(true);
#else
				for (int i=0; i<specNorms->GetNumNormals(); ++i) {
					specNorms->SetNormalExplicit(i, true);
				}
#endif
				specNorms->CheckNormals();
			}
#endif
		}
	}
}
Example #2
0
void SymmetryMod::ModifyTriObject (TimeValue t, ModContext &mc, TriObject *tobj, INode *inode) {
	Mesh &mesh = tobj->GetMesh();
	Interval iv = FOREVER;
	int axis, slice, weld, flip;
	float threshold;

	mp_pblock->GetValue (kSymAxis, t, axis, iv);
	mp_pblock->GetValue (kSymFlip, t, flip, iv);
	mp_pblock->GetValue (kSymSlice, t, slice, iv);
	mp_pblock->GetValue (kSymWeld, t, weld, iv);
	mp_pblock->GetValue (kSymThreshold, t, threshold, iv);
	if (threshold<0) threshold=0;

	// Get transform from mirror controller:
	Matrix3 tm  = CompMatrix (t, NULL, &mc, &iv);
	Matrix3 itm = Inverse (tm);

	// Get DotProd(N,x)=offset plane definition from transform
	Point3 Axis(0,0,0);
	Axis[axis] = flip ? -1.0f : 1.0f;
	Point3 origin = tm.GetTrans();
	Point3 N = Normalize(tm*Axis - origin);
	float offset = DotProd (N, origin);

	// Slice operation does not handle NormalSpecs, but it handles mapping channels.
	// move our mesh normal data to a map channel
	MeshNormalSpec *pNormals = mesh.GetSpecifiedNormals ();
	int normalMapChannel = INVALID_NORMALMAPCHANNEL;
	if (pNormals && pNormals->GetNumFaces())
	{
		pNormals->SetParent(&mesh);
		//find an empty map channel
		for (int mp = 0; mp < mesh.getNumMaps(); mp++) 
		{			
			if (!mesh.mapSupport(mp)) 
			{
				normalMapChannel = mp;

				mesh.setMapSupport(normalMapChannel,TRUE);
				MeshMap& map = mesh.Map(normalMapChannel);
				for (int i = 0; i < map.fnum; i++)
				{
					for (int j = 0; j < 3; j++)
					{
						unsigned int newID = pNormals->Face(i).GetNormalID(j);
						map.tf[i].t[j] = newID;
					}
				}
				map.setNumVerts(pNormals->GetNumNormals());
				for (int i = 0; i < map.vnum; i++)
				{
					map.tv[i] = pNormals->Normal(i);
				}				

				// make sure nothing is done with MeshNormalSpec (until data is copied back) 
				pNormals->Clear();
				break;
			}
		}
	}
	
	// Slice off everything below the plane.
	if (slice) SliceTriObject (mesh, N, offset);
	MirrorTriObject (mesh, axis, tm, itm,normalMapChannel);
	if (weld) WeldTriObject (mesh, N, offset, threshold);

	//now move the normals back
	if (pNormals && normalMapChannel != -1)
	{
		MeshMap& map = mesh.Map(normalMapChannel);
		pNormals->SetNumFaces(map.fnum);

		pNormals->SetNumNormals(map.vnum);
		pNormals->SetAllExplicit(true);
		BitArray temp;
		temp.SetSize(map.vnum);
		temp.SetAll();
		pNormals->SpecifyNormals(TRUE,&temp);

		for (int i = 0; i < map.vnum; i++)
		{
			pNormals->GetNormalArray()[i] = map.tv[i];
			pNormals->SetNormalExplicit(i,true);
		}	

		for (int i = 0; i < map.fnum; i++)
		{
			for (int j = 0; j < 3; j++)
			{
				pNormals->SetNormalIndex(i,j,map.tf[i].t[j]);				
				MeshNormalFace& face = pNormals->Face(i);
				face.SpecifyAll(true);
			}
		}

		pNormals->SetFlag(MESH_NORMAL_MODIFIER_SUPPORT);

		for (int i = 0; i < pNormals->GetNumFaces(); i++)
		{
			for (int j = 0; j < 3; j++)
			{
				int id = pNormals->GetNormalIndex(i,j);	
			}
		}

		pNormals->CheckNormals();
		pNormals->SetParent(NULL);

		// Free the map channel
		mesh.setMapSupport(normalMapChannel,FALSE);
	}
	
	tobj->UpdateValidity (GEOM_CHAN_NUM, iv);
	tobj->UpdateValidity (TOPO_CHAN_NUM, iv);
	tobj->UpdateValidity (VERT_COLOR_CHAN_NUM, iv);
	tobj->UpdateValidity (TEXMAP_CHAN_NUM, iv);
	tobj->UpdateValidity (SELECT_CHAN_NUM, iv);
}