From 7d177c7c224e007367b6143e389c9f94e5a12ac6 Mon Sep 17 00:00:00 2001
From: Gundalf <gundalf01@users.sourceforge.net>
Date: Wed, 28 Jun 2006 18:28:30 +0000
Subject: [PATCH] Proper hierarchies. Port to changed local niflib. Initial
 work for more collision shapes.

---
 NifExport/Coll.cpp         | 362 ++++++++++++++++++++++++++++++++++---
 NifExport/Exporter.cpp     |  78 ++++++--
 NifExport/Exporter.h       |  96 +++++-----
 NifExport/Mesh.cpp         | 130 ++++++++++---
 NifExport/NifExport.vcproj |   2 +-
 NifExport/Util.cpp         |  18 ++
 NifExport/pch.h            |   6 +-
 7 files changed, 590 insertions(+), 102 deletions(-)

diff --git a/NifExport/Coll.cpp b/NifExport/Coll.cpp
index 76ce097..10ace05 100755
--- a/NifExport/Coll.cpp
+++ b/NifExport/Coll.cpp
@@ -1,5 +1,102 @@
 #include "pch.h"
 
+static Class_ID SCUBA_CLASS_ID(0x6d3d77ac, 0x79c939a9);
+
+enum
+{
+	CAPSULE_RADIUS = 0,
+	CAPSULE_HEIGHT = 1,
+};
+
+
+/*
+To mimic the "Reset Transform" and "Reset Scale" behavior, the following code snippet should help:
+
+
+
+	Interface *ip = theResetScale.ip;
+	TimeValue t = ip->GetTime();
+	
+	Control *tmControl = node->GetTMController();
+	BOOL lookAt = tmControl->GetRollController() ? TRUE : FALSE;
+
+	Matrix3 ntm = node->GetNodeTM(t);
+	Matrix3 ptm = node->GetParentTM(t);
+	Matrix3 rtm = ntm * Inverse(ptm);
+	Matrix3 otm(1);
+	Quat rot;
+
+	// Grab the trans, and then set it to 0
+	Point3 trans = rtm.GetTrans();
+	rtm.NoTrans();
+	
+	// We're only doing scale - save out the 
+	// rotation so we can put it back
+	AffineParts parts;
+	decomp_affine(rtm, &parts);
+	rot = parts.q;
+
+	// Build the offset tm
+	otm.PreTranslate(node->GetObjOffsetPos()); 
+	if (node->GetObjOffsetRot()!=IdentQuat()) {
+	   	PreRotateMatrix(otm,node->GetObjOffsetRot());
+		}
+
+	Point3 tS(1,1,1);
+	if ( node->GetObjOffsetScale().s != tS ) {
+		ApplyScaling(otm,node->GetObjOffsetScale());
+		}
+	
+	// Apply the relative tm to the offset
+	otm = otm * rtm;
+	decomp_affine(otm, &parts);
+	node->SetObjOffsetPos(parts.t);	
+	node->SetObjOffsetScale(ScaleValue(parts.k*parts.f,parts.u));
+
+	// Now set the transform controller with a matrix 
+	// that has no rotation or scale
+	rtm.IdentityMatrix();
+	rtm.SetTrans(trans);
+	if (!lookAt) {
+		PreRotateMatrix(rtm,rot);
+		}
+
+	// But first, want to keep children stationary.
+	Matrix3 ttm = rtm*ptm;
+	for (int i=0; iNumberOfChildren(); i++)  {
+		Control *tmc  = node->GetChildNode(i)->GetTMController();
+		Matrix3 oldtm = node->GetChildNode(i)->GetNodeTM(t);
+		SetXFormPacket pk(oldtm,ttm);
+		tmc->SetValue(t,&pk);
+		}
+
+  	SetXFormPacket pckt(rtm);
+	tmControl->SetValue(t,&pckt);		
+
+
+
+To mimic the "Align to world" behavior, the following code snippet should help:
+
+
+
+    AffineParts parts;
+    TimeValue currtime = m_pInterface->GetTime();
+    Matrix3 m = pNode->GetNodeTM(currtime);
+    decomp_affine(m, &parts); 
+    if (rotobj) {
+        // if "affect obj only" we move it simply thus:
+        pNode->SetObjOffsetRot(Inverse(parts.q));
+    } else {
+        // otherwise, "affect pivot only" we would do:
+        IdentityTM ident;
+        Matrix3 wax = ident;
+        wax.SetTrans(m.GetTrans());  // world aligned axis,  centered at pivot point
+        pNode->Rotate(currtime, wax, Inverse(parts.q),TRUE,FALSE, PIV_PIVOT_ONLY);
+    }
+    m_pInterface->RedrawViews(m_pInterface->GetTime(),REDRAW_NORMAL,NULL);
+
+*/
+
 int Exporter::addVertex(vector<Vector3> &verts, vector<Vector3> &vnorms, const Point3 &pt, const Point3 &norm)
 {
 	for (int i=0; i<verts.size(); i++)
@@ -27,7 +124,7 @@ void Exporter::addFace(Triangles &tris, vector<Vector3> &verts, vector<Vector3>
 	}
 	tris.push_back(tri);
 }
-
+/*
 bool Exporter::makeCollisionHierarchy(NiNodeRef &parent, INode *node, TimeValue t)
 {	
 	Matrix3 tm = node->GetObjTMAfterWSM(t);
@@ -62,26 +159,6 @@ bool Exporter::makeCollisionHierarchy(NiNodeRef &parent, INode *node, TimeValue
 	Mesh *mesh = &tri->GetMesh();
 	mesh->buildNormals();
 
-	// get data from node
-	int lyr, mtl, msys, qtype;
-	float mass, lindamp, angdamp, frict, maxlinvel, maxangvel, resti, pendepth;
-	Vector3 center;
-
-	npGetProp(node, NP_HVK_LAYER, lyr, NP_DEFAULT_HVK_LAYER);
-	npGetProp(node, NP_HVK_MATERIAL, mtl, NP_DEFAULT_HVK_MATERIAL);
-	npGetProp(node, NP_HVK_MOTION_SYSTEM, msys, NP_DEFAULT_HVK_MOTION_SYSTEM);
-	npGetProp(node, NP_HVK_QUALITY_TYPE, qtype, NP_DEFAULT_HVK_QUALITY_TYPE);
-	npGetProp(node, NP_HVK_MASS, mass, NP_DEFAULT_HVK_MASS);
-	npGetProp(node, NP_HVK_LINEAR_DAMPING, lindamp, NP_DEFAULT_HVK_LINEAR_DAMPING);
-	npGetProp(node, NP_HVK_ANGULAR_DAMPING, angdamp, NP_DEFAULT_HVK_ANGULAR_DAMPING);
-	npGetProp(node, NP_HVK_FRICTION, frict, NP_DEFAULT_HVK_FRICTION);
-	npGetProp(node, NP_HVK_RESTITUTION, resti, NP_DEFAULT_HVK_RESTITUTION);
-	npGetProp(node, NP_HVK_MAX_LINEAR_VELOCITY, maxlinvel, NP_DEFAULT_HVK_MAX_LINEAR_VELOCITY);
-	npGetProp(node, NP_HVK_MAX_ANGULAR_VELOCITY, maxangvel, NP_DEFAULT_HVK_MAX_ANGULAR_VELOCITY);
-	npGetProp(node, NP_HVK_PENETRATION_DEPTH, pendepth, NP_DEFAULT_HVK_PENETRATION_DEPTH);
-	npGetProp(node, NP_HVK_CENTER, center);
-
-
 	// setup shape data
 	vector<Vector3> verts;
 	vector<Vector3> vnorms;
@@ -160,3 +237,246 @@ bool Exporter::makeCollisionHierarchy(NiNodeRef &parent, INode *node, TimeValue
 
 	return true;
 }
+*/
+
+Exporter::Result Exporter::exportCollision(NiNodeRef &parent, INode *node)
+{
+	// marked as collision?
+	NiNodeRef newParent;
+	if (npIsCollision(node))
+	{
+/*		NiNodeRef n = DynamicCast<NiNode>(CreateBlock("NiNode"));
+		parent->AddChild(DynamicCast<NiAVObject>(n));
+
+		Matrix33 rot;
+		Vector3 trans;
+		TimeValue t = 0;
+		nodeTransform(rot, trans, node, t);
+		n->SetLocalRotation(rot);
+		n->SetLocalTranslation(trans);
+		string name = (char*)node->GetName();
+		n->SetName(name);
+
+
+/*		Vector3 trans;
+		QuaternionXYZW q;
+		TimeValue t = 0;
+		nodeTransform(q, trans, node, t, false);
+		body->SetRotation(q);
+		body->SetTranslation(Vector3(trans.x/7, trans.y/7, trans.z/7));
+*/
+		newParent = makeNode(parent, node);
+
+		bhkSphereRepShapeRef shape = makeCollisionShape(node);
+		bhkRigidBodyRef body = makeCollisionBody(node);
+		body->SetShape(DynamicCast<bhkShape>(shape));
+
+		bhkCollisionObjectRef co = DynamicCast<bhkCollisionObject>(CreateBlock("bhkCollisionObject"));
+		co->SetBody(DynamicCast<NiObject>(body));
+		co->SetParent(newParent);
+
+		// link
+		newParent->SetCollisionObject(DynamicCast<NiCollisionObject>(co));
+
+	} else
+	if (node->IsGroupHead())
+	{
+		newParent = makeNode(parent, node);
+	} else
+		newParent = parent;
+
+	for (int i=0; i<node->NumberOfChildren(); i++) 
+	{
+		Result result = exportCollision(newParent, node->GetChildNode(i));
+		if (result!=Ok && result!=Skip)
+			return result;
+	}
+
+	return Ok;
+}
+
+
+bhkRigidBodyRef Exporter::makeCollisionBody(INode *node)
+{
+	// get data from node
+	int lyr, mtl, msys, qtype;
+	float mass, lindamp, angdamp, frict, maxlinvel, maxangvel, resti, pendepth;
+	Vector3 center;
+
+	npGetProp(node, NP_HVK_LAYER, lyr, NP_DEFAULT_HVK_LAYER);
+	npGetProp(node, NP_HVK_MATERIAL, mtl, NP_DEFAULT_HVK_MATERIAL);
+	npGetProp(node, NP_HVK_MOTION_SYSTEM, msys, NP_DEFAULT_HVK_MOTION_SYSTEM);
+	npGetProp(node, NP_HVK_QUALITY_TYPE, qtype, NP_DEFAULT_HVK_QUALITY_TYPE);
+	npGetProp(node, NP_HVK_MASS, mass, NP_DEFAULT_HVK_MASS);
+	npGetProp(node, NP_HVK_LINEAR_DAMPING, lindamp, NP_DEFAULT_HVK_LINEAR_DAMPING);
+	npGetProp(node, NP_HVK_ANGULAR_DAMPING, angdamp, NP_DEFAULT_HVK_ANGULAR_DAMPING);
+	npGetProp(node, NP_HVK_FRICTION, frict, NP_DEFAULT_HVK_FRICTION);
+	npGetProp(node, NP_HVK_RESTITUTION, resti, NP_DEFAULT_HVK_RESTITUTION);
+	npGetProp(node, NP_HVK_MAX_LINEAR_VELOCITY, maxlinvel, NP_DEFAULT_HVK_MAX_LINEAR_VELOCITY);
+	npGetProp(node, NP_HVK_MAX_ANGULAR_VELOCITY, maxangvel, NP_DEFAULT_HVK_MAX_ANGULAR_VELOCITY);
+	npGetProp(node, NP_HVK_PENETRATION_DEPTH, pendepth, NP_DEFAULT_HVK_PENETRATION_DEPTH);
+	npGetProp(node, NP_HVK_CENTER, center);
+
+	// setup body
+	bhkRigidBodyRef body = DynamicCast<bhkRigidBody>(CreateBlock("bhkRigidBody"));
+
+	body->SetLayer(lyr);
+	body->SetLayerCopy(lyr);
+	body->SetMotionSystem(msys);
+	body->SetQualityType(qtype);
+	body->SetMass(mass);
+	body->SetLinearDamping(lindamp);
+	body->SetAngularDamping(angdamp);
+	body->SetFriction(frict);
+	body->SetRestitution(resti);
+	body->SetMaxLinearVelocity(maxlinvel);
+	body->SetMaxAngularVelocity(maxangvel);
+	body->SetPenetrationDepth(pendepth);
+	body->SetCenter(center);
+
+	return body;
+}
+
+bhkSphereRepShapeRef Exporter::makeCollisionShape(INode *node)
+{
+	bhkSphereRepShapeRef shape;
+	
+	TimeValue t = 0;
+	ObjectState os = node->EvalWorldState(t); 
+	if (os.obj->ClassID() == SCUBA_CLASS_ID)
+		shape = makeCapsuleShape(os.obj);
+	else
+	if (os.obj->ClassID() == Class_ID(BOXOBJ_CLASS_ID, 0))
+		shape = makeBoxShape(os.obj);
+	else
+	if (os.obj->ClassID() == Class_ID(SPHERE_CLASS_ID, 0))
+		shape = makeSphereShape(os.obj);
+	else
+	if (os.obj->SuperClassID() == GEOMOBJECT_CLASS_ID)
+		shape = makeTriStripsShape(node);
+
+	if (shape)
+	{
+		int mtl;
+		npGetProp(node, NP_HVK_MATERIAL, mtl, NP_DEFAULT_HVK_MATERIAL);
+		shape->SetMaterial(mtl);
+	}
+
+	return shape;
+}
+
+bhkSphereRepShapeRef Exporter::makeBoxShape(Object *obj)
+{
+	float length = 0;
+	float height = 0;
+	float width = 0; 
+	IParamArray *params = obj->GetParamBlock();
+	params->GetValue(obj->GetParamBlockIndex(BOXOBJ_LENGTH), 0, length, FOREVER);
+	params->GetValue(obj->GetParamBlockIndex(BOXOBJ_HEIGHT), 0, height, FOREVER);
+	params->GetValue(obj->GetParamBlockIndex(BOXOBJ_WIDTH), 0, width, FOREVER);
+
+	bhkBoxShapeRef box = DynamicCast<bhkBoxShape>(CreateBlock("bhkBoxShape"));
+	box->SetDimensions(Vector3(width, height, length));
+
+	return bhkSphereRepShapeRef(DynamicCast<bhkSphereRepShape>(box));
+}
+
+bhkSphereRepShapeRef Exporter::makeSphereShape(Object *obj)
+{
+	float radius = 0;
+	IParamArray *params = obj->GetParamBlock();
+	params->GetValue(obj->GetParamBlockIndex(SPHERE_RADIUS), 0, radius, FOREVER);
+
+	bhkSphereShapeRef sphere = DynamicCast<bhkSphereShape>(CreateBlock("bhkSphereShape"));
+	sphere->SetRadius(radius);
+
+	return bhkSphereRepShapeRef(DynamicCast<bhkSphereRepShape>(sphere));
+}
+
+bhkSphereRepShapeRef Exporter::makeCapsuleShape(Object *obj)
+{
+	float radius = 0;
+	float height = 0;
+	IParamArray *params = obj->GetParamBlock();
+	params->GetValue(obj->GetParamBlockIndex(CAPSULE_RADIUS), 0, radius, FOREVER);
+	params->GetValue(obj->GetParamBlockIndex(CAPSULE_HEIGHT), 0, height, FOREVER);
+
+	bhkCapsuleShapeRef capsule = DynamicCast<bhkCapsuleShape>(CreateBlock("bhkCapsuleShape"));
+
+	return bhkSphereRepShapeRef(DynamicCast<bhkSphereRepShape>(capsule));
+}
+
+bhkSphereRepShapeRef Exporter::makeTriStripsShape(INode *node)
+{
+	TimeValue t = 0;
+	Matrix3 tm = node->GetObjTMAfterWSM(t);
+
+	// Order of the vertices. Get 'em counter clockwise if the objects is
+	// negatively scaled.
+	int vi[3];
+	if (TMNegParity(tm)) 
+	{
+		vi[0] = 2;
+		vi[1] = 1;
+		vi[2] = 0;
+	} else 
+	{
+		vi[0] = 0;
+		vi[1] = 1;
+		vi[2] = 2;
+	}
+
+	ObjectState os = node->EvalWorldState(t);
+
+	TriObject *tri = (TriObject *)os.obj->ConvertToType(t, Class_ID(TRIOBJ_CLASS_ID, 0));
+	if (!tri)
+		return false;
+
+	Mesh *mesh = &tri->GetMesh();
+	mesh->buildNormals();
+
+	// setup shape data
+	vector<Vector3> verts;
+	vector<Vector3> vnorms;
+	Triangles		tris;
+
+	for (int i=0; i<mesh->getNumFaces(); i++)
+		addFace(tris, verts, vnorms, i, vi, mesh);
+
+	TriStrips strips;
+	strippify(strips, verts, vnorms, tris);
+	NiTriStripsDataRef data = makeTriStripsData(strips);
+	data->SetVertices(verts);
+	data->SetNormals(vnorms);
+
+	// setup shape
+	bhkNiTriStripsShapeRef shape = DynamicCast<bhkNiTriStripsShape>(CreateBlock("bhkNiTriStripsShape"));
+	shape->SetNumStripsData(1);
+	shape->SetStripsData(0, data);
+/*
+	array<float, 2> unknownFloats1;
+	uint i1 = 0x3DCCCCCD;
+	uint i2 = 0x004ABE60;
+	unknownFloats1[0] = *((float*)&i1);
+	unknownFloats1[1] = *((float*)&i2);
+	shape->SetUnknownFloats1(unknownFloats1);
+
+	array<float, 3> unknownFloats2;
+	unknownFloats2[0] = 1;
+	unknownFloats2[1] = 1;
+	unknownFloats2[2] = 1;
+	shape->SetUnknownFloats2(unknownFloats2);
+*/
+/*	array<uint, 5> unknownInts1;
+	unknownInts1[4] = 1;
+	shape->SetUnknownInts1(unknownInts1);
+*/
+	vector<uint> unknownInts2;
+	unknownInts2.resize(1);
+	shape->SetUnknownInts2(unknownInts2);
+
+	if (tri != os.obj)
+		tri->DeleteMe();
+
+	return bhkSphereRepShapeRef(DynamicCast<bhkSphereRepShape>(shape));
+}
diff --git a/NifExport/Exporter.cpp b/NifExport/Exporter.cpp
index dfb713e..e60f07f 100755
--- a/NifExport/Exporter.cpp
+++ b/NifExport/Exporter.cpp
@@ -32,10 +32,25 @@ Exporter::Result Exporter::export(NiNodeRef &root, INode *node)
 	root->AddExtraData(DynamicCast<NiExtraData>(strings));
 
 	mNiRoot = root;
-	return exportTree(root, node);
+	
+	Result result;
+	result = exportMeshes(root, node);
+	if (result != Ok)
+		return result;
+		
+	if (mExportCollision)
+	{
+	
+		result = exportCollision(root, node);
+		if (result != Ok)
+			return result;
+	}
+	return Ok;
 }
 
-Exporter::Result Exporter::exportTree(NiNodeRef &parent, INode *node)
+#if 0
+
+Exporter::Result Exporter::exportMeshes(NiNodeRef &parent, INode *node)
 {
 	bool coll = npIsCollision(node);
 	if ((coll && !mExportCollision) ||
@@ -60,26 +75,65 @@ Exporter::Result Exporter::exportTree(NiNodeRef &parent, INode *node)
 		parent = n;
 	}
 
+	Result result;
 
 	ObjectState os = node->EvalWorldState(t); 
-
-	Result result;
 	if (os.obj) 
 	{
 		// We look at the super class ID to determine the type of the object.
 		switch(os.obj->SuperClassID()) 
 		{
 			case GEOMOBJECT_CLASS_ID: 
-				if (!coll)
+/*				if (os.obj->ClassID() == SCUBA_CLASS_ID)
 				{
-					result = exportMesh(parent, node, t);
-					if (result != Ok)
-						return result;
+					float radius = 0;
+					float height = 0;
+					IParamArray *params = os.obj->GetParamBlock();
+					params->GetValue(os.obj->GetParamBlockIndex(CAPSULE_RADIUS), 0, radius, FOREVER);
+					params->GetValue(os.obj->GetParamBlockIndex(CAPSULE_HEIGHT), 0, height, FOREVER);
+
+					int foo=1+2;
 				} else
+				if (os.obj->ClassID() == Class_ID(BOXOBJ_CLASS_ID, 0))
 				{
-					if (!makeCollisionHierarchy(mNiRoot, node, t))
-						return Error;
+					float length = 0;
+					float height = 0;
+					float width = 0; 
+
+					IParamArray *params = os.obj->GetParamBlock();
+					params->GetValue(os.obj->GetParamBlockIndex(BOXOBJ_LENGTH), 0, length, FOREVER);
+					params->GetValue(os.obj->GetParamBlockIndex(BOXOBJ_HEIGHT), 0, height, FOREVER);
+					params->GetValue(os.obj->GetParamBlockIndex(BOXOBJ_WIDTH), 0, width, FOREVER);
+
+					int foo=1+2;
+
+				} else
+				if (os.obj->ClassID() == Class_ID(SPHERE_CLASS_ID, 0))
+				{
+					float radius = 0;
+
+					IParamArray *params = os.obj->GetParamBlock();
+					params->GetValue(os.obj->GetParamBlockIndex(SPHERE_RADIUS), 0, radius, FOREVER);
+
+					int foo=1+2;
+
+				} else
+				{
+*/
+					if (!coll)
+					{
+
+						result = exportMesh(parent, node, t);
+						if (result != Ok)
+							return result;
+					} /*else
+					{
+
+						if (!makeCollisionHierarchy(mNiRoot, node, t))
+							return Error;
+					}
 				}
+*/
 				break;
 /*
 			case CAMERA_CLASS_ID:
@@ -101,7 +155,7 @@ Exporter::Result Exporter::exportTree(NiNodeRef &parent, INode *node)
 
 	for (int i=0; i<node->NumberOfChildren(); i++) 
 	{
-		Result result = exportTree(parent, node->GetChildNode(i));
+		Result result = exportMeshes(parent, node->GetChildNode(i));
 		if (result!=Ok && result!=Skip)
 			return result;
 	}
@@ -111,3 +165,5 @@ Exporter::Result Exporter::exportTree(NiNodeRef &parent, INode *node)
 
 	return Ok;
 }
+
+#endif
diff --git a/NifExport/Exporter.h b/NifExport/Exporter.h
index 34d0457..3154d3b 100755
--- a/NifExport/Exporter.h
+++ b/NifExport/Exporter.h
@@ -19,24 +19,24 @@ public:
 	};
 
 	/* exporter version */
-	static int			mVersion;
+	static int				mVersion;
 
 	/* export options, static for dialog usage. */
 
-	static bool			mSelectedOnly;
-	static bool			mTriStrips;
-	static bool			mExportHidden;
-	static bool			mExportFurn;
-	static bool			mExportLights;
-	static string		mTexPrefix;
-	static bool			mVertexColors;
-	static float		mWeldThresh;
-	static bool			mExportCollision;
-	static bool			mRemapIndices;
+	static bool				mSelectedOnly;
+	static bool				mTriStrips;
+	static bool				mExportHidden;
+	static bool				mExportFurn;
+	static bool				mExportLights;
+	static string			mTexPrefix;
+	static bool				mVertexColors;
+	static float			mWeldThresh;
+	static bool				mExportCollision;
+	static bool				mRemapIndices;
 
 	Exporter(Interface *i);
 
-	Result				export(NiNodeRef &root, INode *node);
+	Result					export(NiNodeRef &root, INode *node);
 
 	/* config is written to the registry and the root node
 	of the scene, so that it is restored when opening it
@@ -44,14 +44,14 @@ public:
 	use the settings stored in the registry. */
 
 	// writes config to root node
-	static void			writeConfig(INode *node);
+	static void				writeConfig(INode *node);
 	// writes config to registry
-	static void			writeConfig();
+	static void				writeConfig();
 
 	// reads config from root node
-	static void			readConfig(INode *node);
+	static void				readConfig(INode *node);
 	// reads config from registry
-	static void			readConfig();
+	static void				readConfig();
 
 private:
 
@@ -71,51 +71,63 @@ private:
 	// maps face groups to material ID
 	typedef std::map<int, FaceGroup>	FaceGroups;	
 
-	Interface			*mI;
-	NiNodeRef			mNiRoot;
+	Interface				*mI;
+	NiNodeRef				mNiRoot;
 
-	Result				exportTree(NiNodeRef &root, INode *node);
+	Result					exportCollision(NiNodeRef &root, INode *node);
+	Result					exportMeshes(NiNodeRef &root, INode *node);
 
 	/* utility functions */
-	Mtl					*getMaterial(INode *node, int subMtl);
-	bool				TMNegParity(const Matrix3 &m);
-	void				convertMatrix(Matrix33 &dst, const Matrix3 &src);
-	void				nodeTransform(Matrix33 &rot, Vector3 &trans, INode *node, TimeValue t, bool local=true);
-	void				nodeTransform(QuaternionXYZW &rot, Vector3 &trans, INode *node, TimeValue t, bool local=true);
-	Point3				getVertexNormal(Mesh* mesh, int faceNo, RVertex* rv);
-	bool				equal(const Vector3 &a, const Point3 &b, float thresh);
-	BitmapTex			*getTexture(Mtl *mtl);
-	void				getTextureMatrix(Matrix3 &mat, Mtl *mtl);
+	Mtl						*getMaterial(INode *node, int subMtl);
+	bool					TMNegParity(const Matrix3 &m);
+	void					convertMatrix(Matrix33 &dst, const Matrix3 &src);
+	void					nodeTransform(Matrix33 &rot, Vector3 &trans, INode *node, TimeValue t, bool local=true);
+	void					nodeTransform(QuaternionXYZW &rot, Vector3 &trans, INode *node, TimeValue t, bool local=true);
+	Point3					getVertexNormal(Mesh* mesh, int faceNo, RVertex* rv);
+	bool					equal(const Vector3 &a, const Point3 &b, float thresh);
+	BitmapTex				*getTexture(Mtl *mtl);
+	void					getTextureMatrix(Matrix3 &mat, Mtl *mtl);
+	NiNodeRef				makeNode(NiNodeRef &parent, INode *maxNode, bool local=true);
 
 	/* tristrips */
-	void				strippify(TriStrips &strips, vector<Vector3> &verts, vector<Vector3> &norms, const Triangles &tris);
-	void				strippify(TriStrips &strips, FaceGroup &grp);
-	NiTriStripsDataRef	makeTriStripsData(const TriStrips &strips);
+	void					strippify(TriStrips &strips, vector<Vector3> &verts, vector<Vector3> &norms, const Triangles &tris);
+	void					strippify(TriStrips &strips, FaceGroup &grp);
+	NiTriStripsDataRef		makeTriStripsData(const TriStrips &strips);
 
 	/* mesh export */
 	// adds a vertex to a face group if it doesn't exist yet. returns new or previous index into the
 	// vertex array.
-	int 				addVertex(FaceGroup &grp, int face, int vi, Mesh *mesh, const Matrix3 &texm);
+	int 					addVertex(FaceGroup &grp, int face, int vi, Mesh *mesh, const Matrix3 &texm);
 	// adds a face to a face group
-	void				addFace(FaceGroup &grp, int face, const int vi[3], Mesh *mesh, const Matrix3 &texm);
+	void					addFace(FaceGroup &grp, int face, const int vi[3], Mesh *mesh, const Matrix3 &texm);
 	// creates face groups from faces with same sub material id
-	bool				splitMesh(INode *node, Mesh *, FaceGroups &grps, TimeValue t);
+	bool					splitMesh(INode *node, Mesh *, FaceGroups &grps, TimeValue t);
 	// creates a NiTriStrips or NiTriShape hierarchy from a face group
-	bool				makeMesh(NiNodeRef &parent, Mtl *mtl, FaceGroup &grp);
+	bool					makeMesh(NiNodeRef &parent, Mtl *mtl, FaceGroup &grp);
 	// splits mesh and converts it into nif blocks
-	Result				exportMesh(NiNodeRef &parent, INode *node, TimeValue t);
+	Result					exportMesh(NiNodeRef &parent, INode *node, TimeValue t);
 
 	/* texture & material */
 	// creates NiTexturingProperty + NiSourceTexture
-	void				makeTexture(NiAVObjectRef &parent, Mtl *mtl);
+	void					makeTexture(NiAVObjectRef &parent, Mtl *mtl);
 	// creates a NiMaterialProperty
-	void				makeMaterial(NiAVObjectRef &parent, Mtl *mtl);
+	void					makeMaterial(NiAVObjectRef &parent, Mtl *mtl);
 
 	/* havok & collision */
-	int					addVertex(vector<Vector3> &verts, vector<Vector3> &vnorms, const Point3 &pt, const Point3 &norm);
-	void				addFace(Triangles &tris, vector<Vector3> &verts, vector<Vector3> &vnorms, 
-		                    int face, const int vi[3], Mesh *mesh);
-	bool				makeCollisionHierarchy(NiNodeRef &parent, INode *node, TimeValue t);
+	int						addVertex(vector<Vector3> &verts, vector<Vector3> &vnorms, const Point3 &pt, const Point3 &norm);
+	void					addFace(Triangles &tris, vector<Vector3> &verts, vector<Vector3> &vnorms, 
+								int face, const int vi[3], Mesh *mesh);
+	bool					makeCollisionHierarchy(NiNodeRef &parent, INode *node, TimeValue t);
+	
+	/* creates a bhkRigidBody */
+	bhkRigidBodyRef			makeCollisionBody(INode *node);
+	/* creates a collision shape from a node */
+	bhkSphereRepShapeRef	makeCollisionShape(INode *node);
+
+	bhkSphereRepShapeRef	makeTriStripsShape(INode *node);
+	bhkSphereRepShapeRef	makeBoxShape(Object *obj);
+	bhkSphereRepShapeRef	makeSphereShape(Object *obj);
+	bhkSphereRepShapeRef	makeCapsuleShape(Object *obj);
 };
 
 #endif 
diff --git a/NifExport/Mesh.cpp b/NifExport/Mesh.cpp
index 5324500..2f7af6f 100755
--- a/NifExport/Mesh.cpp
+++ b/NifExport/Mesh.cpp
@@ -1,39 +1,117 @@
 #include "pch.h"
 
-Exporter::Result Exporter::exportMesh(NiNodeRef &parent, INode *node, TimeValue t)
+/*
+
+void FPUtility::GetAlphaVal(void)
+{
+	if(ip->GetSelNodeCount()<1)return;
+	INode *node = ip->GetSelNode(0);
+	if(!node)return;
+ 	ObjectState os = node->EvalWorldState(0);
+	Object *obj = os.obj;
+	BOOL delMesh = false;
+
+	if (obj && obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) { 
+		TriObject * tri = NULL;
+		tri = (TriObject *) obj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0));
+		if (obj != tri) 
+			delMesh = true; // we own the copy
+		if (tri) 
+		{
+			Mesh * mesh = &(tri->GetMesh());
+			MeshDelta md(*mesh);
+			BOOL support = mesh->mapSupport(MAP_ALPHA);
+			if(support)
+			{
+				UVVert *alpha = mesh->mapVerts(MAP_ALPHA);
+				for(int i=0;igetNumVerts();i++)
+				{
+					float a = alpha[i].x;
+				}
+			}
+
+		}
+
+		if (delMesh)
+			delete tri;
+	}
+}
+				
+*/
+
+
+Exporter::Result Exporter::exportMeshes(NiNodeRef &parent, INode *node)
+{
+	bool coll = npIsCollision(node);
+	if ((coll && !mExportCollision) ||
+		(node->IsHidden() && !mExportHidden && !coll) ||
+		(mSelectedOnly && !node->Selected()))
+		return Skip;
+
+	NiNodeRef newParent;
+	TimeValue t = 0;
+	ObjectState os = node->EvalWorldState(t); 
+	if (!coll && os.obj && os.obj->SuperClassID()==GEOMOBJECT_CLASS_ID)
+	{
+/*		newParent = DynamicCast<NiNode>(CreateBlock("NiNode"));
+		parent->AddChild(DynamicCast<NiAVObject>(newParent));
+
+		Matrix33 rot;
+		Vector3 trans;
+		nodeTransform(rot, trans, node, t);
+
+		newParent->SetLocalRotation(rot);
+		newParent->SetLocalTranslation(trans);
+		string name = (char*)node->GetName();
+		newParent->SetName(name);
+*/
+		newParent = makeNode(parent, node);
+
+		Result result;
+		result = exportMesh(newParent, node, t);
+		if (result != Ok)
+			return result;
+
+	} else
+	if (node->IsGroupHead())
+	{
+		newParent = makeNode(parent, node);
+/*		newParent = DynamicCast<NiNode>(CreateBlock("NiNode"));
+		Matrix33 rot;
+		Vector3 trans;
+		nodeTransform(rot, trans, node, t);
+		newParent->SetLocalRotation(rot);
+		newParent->SetLocalTranslation(trans);
+		string name = (char*)node->GetName();
+		newParent->SetName(name);
+
+		parent->AddChild(DynamicCast<NiAVObject>(newParent));
+*/
+	} else
+		newParent = parent;
+
+	for (int i=0; i<node->NumberOfChildren(); i++) 
+	{
+		Result result = exportMeshes(newParent, node->GetChildNode(i));
+		if (result!=Ok && result!=Skip)
+			return result;
+	}
+
+	return Ok;
+}
+
+
+Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue t)
 {	
 	ObjectState os = node->EvalWorldState(t);
-	if (!os.obj || os.obj->SuperClassID()!=GEOMOBJECT_CLASS_ID)
-		return Error;
-		
-	BOOL alloc;
-	Object *obj = os.obj;
-	if (!obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) 
-		return Error;
 
-	TriObject *tri = (TriObject *) obj->ConvertToType(t, Class_ID(TRIOBJ_CLASS_ID, 0));
+	TriObject *tri = (TriObject *)os.obj->ConvertToType(t, Class_ID(TRIOBJ_CLASS_ID, 0));
 	if (!tri)
 		return Error;
 
-	if (obj != tri) 
-		alloc = TRUE;
-	else
-		alloc = FALSE;
-
 	Mesh *mesh = &tri->GetMesh();
 	mesh->buildNormals();
 
-	Matrix33 rot;
-	Vector3 trans;
-	nodeTransform(rot, trans, node, t);
-
-	NiNodeRef ninode = DynamicCast<NiNode>(CreateBlock("NiNode"));
-	ninode->SetLocalRotation(rot);
-	ninode->SetLocalTranslation(trans);
-	string name = (char*)node->GetName();
-	ninode->SetName(name);
-	parent->AddChild(DynamicCast<NiAVObject>(ninode));
-
 	Result result = Ok;
 	while (1)
 	{
@@ -57,7 +135,7 @@ Exporter::Result Exporter::exportMesh(NiNodeRef &parent, INode *node, TimeValue
 		break;
 	}
 
-	if (alloc)
+	if (tri != os.obj)
 		tri->DeleteMe();
 
 	return result;
diff --git a/NifExport/NifExport.vcproj b/NifExport/NifExport.vcproj
index 16d2155..82855bc 100755
--- a/NifExport/NifExport.vcproj
+++ b/NifExport/NifExport.vcproj
@@ -36,7 +36,7 @@
 				RuntimeLibrary="2"
 				BufferSecurityCheck="FALSE"
 				EnableFunctionLevelLinking="TRUE"
-				UsePrecompiledHeader="1"
+				UsePrecompiledHeader="0"
 				PrecompiledHeaderThrough="pch.h"
 				PrecompiledHeaderFile=".\Release\NifExport.pch"
 				AssemblerListingLocation=".\Release\"
diff --git a/NifExport/Util.cpp b/NifExport/Util.cpp
index 39822c4..2c072ce 100755
--- a/NifExport/Util.cpp
+++ b/NifExport/Util.cpp
@@ -87,3 +87,21 @@ bool Exporter::equal(const Vector3 &a, const Point3 &b, float thresh)
 		   (fabsf(a.y-b.y) <= thresh) &&
 		   (fabsf(a.z-b.z) <= thresh);
 }
+
+NiNodeRef Exporter::makeNode(NiNodeRef &parent, INode *maxNode, bool local)
+{
+	NiNodeRef node = DynamicCast<NiNode>(CreateBlock("NiNode"));
+	
+	Matrix33 rot;
+	Vector3 trans;
+	TimeValue t = 0;
+	nodeTransform(rot, trans, maxNode, t, local);
+	
+	node->SetLocalRotation(rot);
+	node->SetLocalTranslation(trans);
+	string name = (char*)maxNode->GetName();
+	node->SetName(name);
+
+	parent->AddChild(DynamicCast<NiAVObject>(node));
+	return node;
+}
diff --git a/NifExport/pch.h b/NifExport/pch.h
index 31b1b22..a2a4a78 100755
--- a/NifExport/pch.h
+++ b/NifExport/pch.h
@@ -12,13 +12,17 @@
 // niflib/Ref.h' header guard caused havok!
 // near & far 
 #include "niflib/pch.h"
+#include "niflib/obj/NiNode.h"
 #include "niflib/obj/NiTriStrips.h"
 #include "niflib/obj/NiTriStripsData.h"
 #include "niflib/obj/NiTriShape.h"
 #include "niflib/obj/NiTriShapeData.h"
 #include "niflib/obj/bhkCollisionObject.h"
-#include "niflib/obj/bhkRigidBodyT.h"
+#include "niflib/obj/bhkRigidBody.h"
 #include "niflib/obj/bhkNiTriStripsShape.h"
+#include "niflib/obj/bhkBoxShape.h"
+#include "niflib/obj/bhkSphereShape.h"
+#include "niflib/obj/bhkCapsuleShape.h"
 #include "niflib/obj/NiMaterialProperty.h"
 #include "niflib/obj/NiTexturingProperty.h"
 #include "niflib/obj/NiSourceTexture.h"
-- 
GitLab