Newer
Older
#include "../NifProps/bhkRigidBodyInterface.h"
#include "obj/bhkTransformShape.h"
#include "obj/bhkSphereShape.h"
#include "obj/bhkBoxShape.h"
#include "obj/bhkCapsuleShape.h"
#include "obj/hkPackedNiTriStripsData.h"
#include "obj/bhkPackedNiTriStripsShape.h"
#include "..\NifProps\bhkHelperFuncs.h"
#include "..\NifProps\bhkHelperInterface.h"
#ifdef _DEBUG
#include <assert.h>
#include <crtdbg.h>
#define ASSERT _ASSERTE
#else
#define ASSERT(x)
#endif
Gundalf
committed
static Class_ID SCUBA_CLASS_ID(0x6d3d77ac, 0x79c939a9);
extern Class_ID bhkBoxObject_CLASS_ID;
extern Class_ID BHKCAPSULEOBJECT_CLASS_ID;
extern Class_ID bhkSphereObject_CLASS_ID;
extern Class_ID BHKPROXYOBJECT_CLASS_ID;
Gundalf
committed
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
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++)
{
if (equal(verts[i], pt, mWeldThresh) &&
equal(vnorms[i], norm, 0))
return i;
}
verts.push_back(Vector3(pt.x, pt.y, pt.z));
vnorms.push_back(Vector3(norm.x, norm.y, norm.z));
return verts.size()-1;
}
void Exporter::addFace(Triangles &tris, vector<Vector3> &verts, vector<Vector3> &vnorms,
Point3 pt = mesh->verts[ mesh->faces[ face ].v[ vi[i] ] ] * tm;
Point3 norm = getVertexNormal(mesh, face, mesh->getRVertPtr(mesh->faces[ face ].v[ vi[i] ])) * tm;
Gundalf
committed
Exporter::Result Exporter::exportCollision(NiNodeRef &parent, INode *node)
{
if (isHandled(node))
return Exporter::Skip;
ProgressUpdate(Collision, FormatText("'%s' Collision", node->GetName()));
Gundalf
committed
// marked as collision?
bool coll = isCollision(node);
bool local = !mFlattenHierarchy;
NiNodeRef nodeParent = mFlattenHierarchy ? mNiRoot : parent;
Gundalf
committed
NiNodeRef newParent;
Gundalf
committed
{
newParent = Exporter::findNode(node->GetParentNode());
//newParent = nodeParent; // always have collision one level up?
Gundalf
committed
TimeValue t = 0;
Gundalf
committed
bhkRigidBodyRef body = makeCollisionBody(node);
bool hasTrans = (body->IsDerivedType(bhkRigidBodyT::TYPE));
Matrix3 tm = getTransform(node, t, false); // has transform
Matrix3 pm = TOMATRIX3(newParent->GetWorldTransform());
tm = tm * Inverse(pm);
Matrix44 rm4 = TOMATRIX4(tm, false);
Vector3 trans; Matrix33 rm; float scale;
rm4.Decompose(trans, rm, scale);
QuaternionXYZW q = TOQUATXYZW(rm.AsQuaternion());
body->SetRotation(q);
body->SetTranslation(trans / Exporter::bhkScaleFactor);
if (hasTrans) {
tm = getTransform(node, t, false);
tm.NoScale();
tm.Invert();
} else {
tm = TOMATRIX3(newParent->GetWorldTransform());
tm.NoScale();
tm.Invert();
//tm.IdentityMatrix();
}
bhkShapeRef shape = makeCollisionShape(node, tm, body);
if (shape)
{
body->SetShape(DynamicCast<bhkShape>(shape));
bhkCollisionObjectRef co = new bhkCollisionObject();
co->SetBody(DynamicCast<NiObject>(body));
newParent->SetCollisionObject(DynamicCast<NiCollisionObject>(co));
}
} else if (isCollisionGroup(node) && !mFlattenHierarchy) {
newParent = makeNode(nodeParent, node);
} else {
newParent = Exporter::findNode(node->GetParentNode());
if (!newParent)
newParent = nodeParent;
if (!newParent)
newParent = nodeParent;
Gundalf
committed
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 = NP_DEFAULT_HVK_LAYER;
int mtl = NP_DEFAULT_HVK_MATERIAL;
int msys = NP_DEFAULT_HVK_MOTION_SYSTEM;
int qtype = NP_DEFAULT_HVK_QUALITY_TYPE;
float mass = NP_DEFAULT_HVK_MASS;
float lindamp = NP_DEFAULT_HVK_LINEAR_DAMPING;
float angdamp = NP_DEFAULT_HVK_ANGULAR_DAMPING;
float frict = NP_DEFAULT_HVK_FRICTION;
float maxlinvel = NP_DEFAULT_HVK_MAX_LINEAR_VELOCITY;
float maxangvel = NP_DEFAULT_HVK_MAX_ANGULAR_VELOCITY;
float resti = NP_DEFAULT_HVK_RESTITUTION;
float pendepth = NP_DEFAULT_HVK_PENETRATION_DEPTH;
Vector3 center(0,0,0);
if (bhkRigidBodyInterface *irb = (bhkRigidBodyInterface *)node->GetObjectRef()->GetInterface(BHKRIGIDBODYINTERFACE_DESC))
{
mass = irb->GetMass(0);
frict = irb->GetFriction(0);
resti = irb->GetRestitution(0);
lyr = irb->GetLayer(0);
msys = irb->GetMotionSystem(0);
qtype = irb->GetQualityType(0);
lindamp = irb->GetLinearDamping(0);
angdamp = irb->GetAngularDamping(0);
maxlinvel = irb->GetMaxLinearVelocity(0);
pendepth = irb->GetPenetrationDepth(0);
maxangvel = irb->GetMaxAngularVelocity(0);
transenable = irb->GetEnableTransform(0);
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
{
// Handle compatibility
npGetProp(node, NP_HVK_MASS_OLD, mass, NP_DEFAULT_HVK_EMPTY);
if (mass == NP_DEFAULT_HVK_EMPTY)
npGetProp(node, NP_HVK_MASS, mass, NP_DEFAULT_HVK_MASS);
npGetProp(node, NP_HVK_FRICTION_OLD, frict, NP_DEFAULT_HVK_EMPTY);
if (frict == NP_DEFAULT_HVK_EMPTY)
npGetProp(node, NP_HVK_FRICTION, frict, NP_DEFAULT_HVK_FRICTION);
npGetProp(node, NP_HVK_RESTITUTION_OLD, resti, NP_DEFAULT_HVK_EMPTY);
if (resti == NP_DEFAULT_HVK_EMPTY)
npGetProp(node, NP_HVK_RESTITUTION, resti, NP_DEFAULT_HVK_RESTITUTION);
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_LINEAR_DAMPING, lindamp, NP_DEFAULT_HVK_LINEAR_DAMPING);
npGetProp(node, NP_HVK_ANGULAR_DAMPING, angdamp, NP_DEFAULT_HVK_ANGULAR_DAMPING);
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);
}
else
{
// Check self to see if is one of our bhkXXXObject classes
if (Object* obj = node->GetObjectRef())
{
if (obj->SuperClassID() == HELPER_CLASS_ID &&
obj->ClassID().PartB() == BHKRIGIDBODYCLASS_DESC.PartB())
{
// TODO: do standard body export
}
}
// else check redirection
}
Gundalf
committed
// setup body
bhkRigidBodyRef body = transenable ? new bhkRigidBodyT() : new bhkRigidBody();
body->SetLayer(OblivionLayer(lyr));
body->SetLayerCopy(OblivionLayer(lyr));
body->SetMotionSystem(MotionSystem(msys));
body->SetQualityType(MotionQuality(qtype));
Gundalf
committed
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);
QuaternionXYZW q; q.x = q.y = q.z = 0; q.w = 1.0f;
body->SetRotation(q);
Gundalf
committed
return body;
}
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
bhkNiTriStripsShapeRef Exporter::makeTriStripsShape(Mesh& mesh, Matrix3& sm)
{
typedef vector<Triangle> Triangles;
// setup shape data
vector<Vector3> verts;
vector<Vector3> vnorms;
Triangles tris;
int vi[3];
if (TMNegParity(sm)) {
vi[0] = 2; vi[1] = 1; vi[2] = 0;
} else {
vi[0] = 0; vi[1] = 1; vi[2] = 2;
}
for (int i=0; i<mesh.getNumFaces(); i++)
addFace(tris, verts, vnorms, i, vi, &mesh, sm);
NiTriStripsDataRef data = new NiTriStripsData(tris, Exporter::mUseAlternateStripper);
data->SetVertices(verts);
data->SetNormals(vnorms);
// setup shape
bhkNiTriStripsShapeRef shape = StaticCast<bhkNiTriStripsShape>(bhkNiTriStripsShape::Create());
shape->SetNumStripsData(1);
shape->SetStripsData(0, data);
shape->SetNumDataLayers(1);
shape->SetOblivionLayer(0, OL_STATIC);
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
return shape;
}
bhkPackedNiTriStripsShapeRef Exporter::makePackedTriStripsShape(Mesh& mesh, Matrix3& sm)
{
// Need to separate the vertices based on material.
typedef vector<Triangle> Triangles;
// setup shape data
vector<Vector3> verts;
vector<Vector3> norms;
Triangles tris;
int vi[3];
if (TMNegParity(sm)) {
vi[0] = 2; vi[1] = 1; vi[2] = 0;
} else {
vi[0] = 0; vi[1] = 1; vi[2] = 2;
}
int nvert = mesh.getNumVerts();
int nface = mesh.getNumFaces();
mesh.buildNormals();
tris.resize(nface);
verts.resize(nvert);
norms.resize(nface);
for (int i=0; i<nvert; ++i)
{
Point3 vert = (mesh.getVert(i) * sm) / Exporter::bhkScaleFactor;
verts[i] = TOVECTOR3(vert);
}
for (int i=0; i<nface; ++i)
{
Triangle& tri = tris[i];
norms[i] = TOVECTOR3(mesh.getFaceNormal(i));
Face& face = mesh.faces[i];
tri[0] = face.getVert(0);
tri[1] = face.getVert(1);
tri[2] = face.getVert(2);
}
hkPackedNiTriStripsDataRef data = new hkPackedNiTriStripsData();
data->SetNumFaces( tris.size() );
data->SetVertices(verts);
data->SetTriangles(tris);
data->SetNormals(norms);
// setup shape
bhkPackedNiTriStripsShapeRef shape = new bhkPackedNiTriStripsShape();
shape->SetData(data);
//shape->SetStripsData(0, data);
//shape->SetNumDataLayers(1);
//shape->SetOblivionLayer(0, OL_STATIC);
return shape;
}
bhkConvexVerticesShapeRef Exporter::makeConvexShape(Mesh& mesh, Matrix3& tm)
{
bhkConvexVerticesShapeRef shape = StaticCast<bhkConvexVerticesShape>(bhkConvexVerticesShape::Create());
Point3 center(0.0f, 0.0f, 0.0f);
float radius = 0.10f;
//CalcAxisAlignedSphere(mesh, center, radius);
verts[i] = TOVECTOR3(vert);
}
for (int i=0; i<nface; ++i)
{
Float4 &value = norms[i];
Point3 &pt = mesh.getFaceNormal(i);
value[0] = pt.x;
value[1] = pt.y;
value[2] = pt.z;
value[3] = -mesh.FaceCenter(i).Length();
bhkShapeRef Exporter::makeCollisionShape(INode *node, Matrix3& tm, bhkRigidBodyRef body)
Gundalf
committed
{
bhkShapeRef shape;
Gundalf
committed
TimeValue t = 0;
ObjectState os = node->EvalWorldState(t);
if (os.obj->ClassID() == SCUBA_CLASS_ID)
shape = makeCapsuleShape(node, os.obj, tm);
else if (os.obj->ClassID() == Class_ID(BOXOBJ_CLASS_ID, 0))
shape = makeBoxShape(node, os.obj, tm);
else if (os.obj->ClassID() == Class_ID(SPHERE_CLASS_ID, 0))
shape = makeSphereShape(node, os.obj, tm);
else if (os.obj->ClassID() == bhkBoxObject_CLASS_ID)
shape = makebhkBoxShape(node, os.obj, tm);
else if (os.obj->ClassID() == bhkSphereObject_CLASS_ID)
shape = makebhkSphereShape(node, os.obj, tm);
else if (os.obj->ClassID() == BHKCAPSULEOBJECT_CLASS_ID)
shape = makebhkCapsuleShape(node, os.obj, tm);
else if (os.obj->ClassID() == BHKLISTOBJECT_CLASS_ID)
shape = makeListShape(node, tm, body);
else if (os.obj->ClassID() == BHKPROXYOBJECT_CLASS_ID)
shape = makeProxyShape(node, os.obj, tm);
else if (os.obj->SuperClassID() == GEOMOBJECT_CLASS_ID)
{
if (Modifier* mod = GetbhkCollisionModifier(node))
{
shape = makeModifierShape(node, os.obj, mod, tm);
}
else
{
shape = makeTriStripsShape(node, tm);
}
}
Gundalf
committed
return shape;
}
bhkShapeRef Exporter::makeBoxShape(INode *node, Object *obj, Matrix3& tm)
Gundalf
committed
{
Gundalf
committed
float length = 0;
float height = 0;
float width = 0;
if (IParamBlock2* pblock2 = obj->GetParamBlockByID(0))
{
pblock2->GetValue(BOXOBJ_LENGTH, 0, length, FOREVER);
pblock2->GetValue(BOXOBJ_HEIGHT, 0, height, FOREVER);
pblock2->GetValue(BOXOBJ_WIDTH, 0, width, FOREVER);
}
Gundalf
committed
Vector3 dim(width * scale[0], length * scale[1], height * scale[2]);
Gundalf
committed
// Adjust translation for center of z axis in box
tm.Translate(Point3(0.0, 0.0, dim.z / 2.0));
dim /= (Exporter::bhkScaleFactor * 2);
box->SetDimensions(dim);
int mtl = 0;
npGetProp(node, NP_HVK_MATERIAL, mtl, NP_DEFAULT_HVK_MATERIAL);
box->SetMaterial(HavokMaterial(mtl));
return bhkShapeRef(DynamicCast<bhkSphereRepShape>(box));
Gundalf
committed
}
bhkShapeRef Exporter::makeSphereShape(INode *node, Object *obj, Matrix3& tm)
Gundalf
committed
{
Point3 scale = GetScale(tm);
float s = (scale[0] + scale[1] + scale[2]) / 3.0;
Gundalf
committed
float radius = 0;
if (IParamBlock2* pblock2 = obj->GetParamBlockByID(0))
{
pblock2->GetValue(SPHERE_RADIUS, 0, radius, FOREVER);
}
Gundalf
committed
bhkSphereShapeRef sphere = new bhkSphereShape();
sphere->SetRadius(radius * s);
Gundalf
committed
int mtl = 0;
npGetProp(node, NP_HVK_MATERIAL, mtl, NP_DEFAULT_HVK_MATERIAL);
sphere->SetMaterial(HavokMaterial(mtl));
return bhkShapeRef(DynamicCast<bhkSphereRepShape>(sphere));
Gundalf
committed
}
bhkShapeRef Exporter::makeCapsuleShape(INode *node, Object *obj, Matrix3& tm)
Gundalf
committed
{
Point3 scale = GetScale(tm);
float s = (scale[0] + scale[1] + scale[2]) / 3.0;
float radius = 0.1f;
float height = 0.1f;
if (IParamBlock2* params = obj->GetParamBlockByID(0))
{
params->GetValue(CAPSULE_RADIUS, 0, radius, FOREVER);
params->GetValue(CAPSULE_HEIGHT, 0, height, FOREVER);
}
Gundalf
committed
bhkCapsuleShapeRef capsule = CreateNiObject<bhkCapsuleShape>();
Gundalf
committed
capsule->SetRadius(radius);
capsule->SetRadius1(radius);
capsule->SetRadius2(radius);
int mtl = 0;
npGetProp(node, NP_HVK_MATERIAL, mtl, NP_DEFAULT_HVK_MATERIAL);
capsule->SetMaterial(HavokMaterial(mtl));
return bhkShapeRef(DynamicCast<bhkSphereRepShape>(capsule));
Gundalf
committed
}
bhkShapeRef Exporter::makebhkBoxShape(INode *node, Object *obj, Matrix3& tm)
{
enum { box_params, };
enum { PB_MATERIAL, PB_LENGTH, PB_WIDTH, PB_HEIGHT, };
bhkShapeRef retval;
if (IParamBlock2* pblock2 = obj->GetParamBlockByID(box_params))
{
Point3 scale = GetScale(tm);
float s = (scale[0] + scale[1] + scale[2]) / 3.0;
pblock2->GetValue(PB_MATERIAL, 0, mtl, FOREVER, 0);
pblock2->GetValue(PB_LENGTH, 0, length, FOREVER, 0);
pblock2->GetValue(PB_WIDTH, 0, width, FOREVER, 0);
pblock2->GetValue(PB_HEIGHT, 0, height, FOREVER, 0);
bhkBoxShapeRef box = new bhkBoxShape();
Vector3 dim(width * scale[0], length * scale[1], height * scale[2]);
// Adjust translation for center of z axis in box
tm.Translate(Point3(0.0, 0.0, dim.z / 2.0));
box->SetDimensions(dim);
box->SetMaterial(HavokMaterial(mtl));
transform->SetShape(box);
transform->SetMaterial(HavokMaterial(mtl));
retval = StaticCast<bhkShape>(transform);
}
}
return retval;
}
bhkShapeRef Exporter::makebhkSphereShape(INode *node, Object *obj, Matrix3& tm)
{
bhkShapeRef retval;
enum { sphere_params, };
enum { PB_MATERIAL, PB_RADIUS, PB_SEGS, PB_SMOOTH, };
if (IParamBlock2* pblock2 = obj->GetParamBlockByID(sphere_params))
{
float radius = 0.0f;
int mtl = NP_DEFAULT_HVK_MATERIAL;
pblock2->GetValue(PB_RADIUS, 0, radius, FOREVER, 0);
pblock2->GetValue(PB_MATERIAL, 0, mtl, FOREVER, 0);
bhkSphereShapeRef shape = new bhkSphereShape();
shape->SetRadius(radius);
shape->SetMaterial(HavokMaterial(mtl));
transform->SetShape(shape);
transform->SetMaterial(HavokMaterial(mtl));
retval = StaticCast<bhkShape>(transform);
}
}
return retval;
}
bhkShapeRef Exporter::makebhkCapsuleShape(INode *node, Object *obj, Matrix3& tm)
{
bhkShapeRef retval;
enum { cap_params, };
enum { PB_MATERIAL, PB_RADIUS1, PB_RADIUS2, PB_LENGTH, };
if (IParamBlock2* pblock2 = obj->GetParamBlockByID(cap_params))
{
float radius1 = 0.0f, radius2 = 0.0f, len = 0.0f;
int mtl = NP_DEFAULT_HVK_MATERIAL;
pblock2->GetValue(PB_RADIUS1, 0, radius1, FOREVER, 0);
pblock2->GetValue(PB_RADIUS2, 0, radius2, FOREVER, 0);
pblock2->GetValue(PB_LENGTH, 0, len, FOREVER, 0);
pblock2->GetValue(PB_MATERIAL, 0, mtl, FOREVER, 0);
bhkCapsuleShapeRef shape = new bhkCapsuleShape();
shape->SetRadius((radius1 + radius2)/2.0f);
shape->SetRadius1(radius1);
shape->SetRadius2(radius2);
shape->SetMaterial(HavokMaterial(mtl));
Matrix3 ltm = node->GetNodeTM(0) * tm;
Point3 center = ltm.GetTrans();
rot.NoTrans();
rot.NoScale();
float distFromCenter = len*Exporter::bhkScaleFactor/2.0f;
Point3 pt1 = ((TransMatrix(Point3(0.0f, 0.0f, +distFromCenter)) * rot).GetTrans() + center) / Exporter::bhkScaleFactor;
Point3 pt2 = ((TransMatrix(Point3(0.0f, 0.0f, -distFromCenter)) * rot).GetTrans() + center) / Exporter::bhkScaleFactor;
shape->SetFirstPoint(TOVECTOR3(pt1));
shape->SetSecondPoint(TOVECTOR3(pt2));
retval = StaticCast<bhkShape>(shape);
}
bhkShapeRef Exporter::makeTriStripsShape(INode *node, Matrix3& tm)
Gundalf
committed
{
TimeValue t = 0;
Gundalf
committed
// Order of the vertices. Get 'em counter clockwise if the objects is
// negatively scaled.
ObjectState os = node->EvalWorldState(t);
TriObject *tri = (TriObject *)os.obj->ConvertToType(t, Class_ID(TRIOBJ_CLASS_ID, 0));
if (!tri)
return false;
Gundalf
committed
bhkNiTriStripsShapeRef shape = makeTriStripsShape(mesh, sm);
Gundalf
committed
int lyr = OL_STATIC;
npGetProp(node, NP_HVK_LAYER, lyr, NP_DEFAULT_HVK_LAYER);
shape->SetNumDataLayers(1);
shape->SetOblivionLayer(0, OblivionLayer(lyr));
npGetProp(node, NP_HVK_MATERIAL, mtl, NP_DEFAULT_HVK_MATERIAL);
shape->SetMaterial(HavokMaterial(mtl));
return StaticCast<bhkShape>(shape);
Gundalf
committed
}
bhkShapeRef Exporter::makeConvexShape(INode *node, Object* obj, Matrix3& tm)
{
bhkShapeRef shape;
return shape;
}
Exporter::Result Exporter::scanForCollision(INode *node)
{
if (NULL == node)
return Exporter::Skip;
// Get the bhk RigidBody modifier if available and then get the picked node.
if (Modifier * mod = GetbhkCollisionModifier(node)){
if (IParamBlock2* pblock = (IParamBlock2*)mod->GetReference(0)) {
if (INode *collMesh = pblock->GetINode(0, 0)) {
mCollisionNodes.insert(collMesh);
} else {
if (mSceneCollisionNode != NULL) {
if (mExportCollision) {
throw runtime_error("There are more than one Collision mesh found at the Scene Level.");
}
} else {
mSceneCollisionNode = node;
}
}
}
}
// Check self to see if is one of our bhkXXXObject classes
if (Object* obj = node->GetObjectRef())
{
if (obj->ClassID() == BHKLISTOBJECT_CLASS_ID)
{
mCollisionNodes.insert(node);
const int PB_MESHLIST = 1;
IParamBlock2* pblock2 = obj->GetParamBlockByID(0);
int nBlocks = pblock2->Count(PB_MESHLIST);
for (int i = 0;i < pblock2->Count(PB_MESHLIST); i++) {
INode *tnode = NULL;
pblock2->GetValue(PB_MESHLIST,0,tnode,FOREVER,i);
if (tnode != NULL) {
mCollisionNodes.insert(tnode);
markAsHandled(tnode); // dont process collision since the list will
}
}
}
else if (obj->SuperClassID() == HELPER_CLASS_ID &&
obj->ClassID().PartB() == BHKRIGIDBODYCLASS_DESC.PartB())
{
mCollisionNodes.insert(node);
}
else
{
Modifier* mod = GetbhkCollisionModifier(node);
if (mod != NULL)
{
mCollisionNodes.insert(node);
}
}
if (npIsCollision(node))
{
mCollisionNodes.insert(node);
}
for (int i=0; i<node->NumberOfChildren(); i++) {
scanForCollision(node->GetChildNode(i));
}
return Exporter::Ok;
}
bool Exporter::isHandled(INode *node)
{
return (mHandledNodes.find(node) != mHandledNodes.end());
}
bool Exporter::markAsHandled(INode* node)
{
mHandledNodes.insert(node);
return true;
}
bool Exporter::isCollision(INode *node)
{
return (mCollisionNodes.find(node) != mCollisionNodes.end());
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
}
bhkShapeRef Exporter::makeListShape(INode *node, Matrix3& tm, bhkRigidBodyRef body)
{
const int PB_MATERIAL = 0;
const int PB_MESHLIST = 1;
IParamBlock2* pblock2 = node->GetObjectRef()->GetParamBlockByID(0);
int nBlocks = pblock2->Count(PB_MESHLIST);
if (nBlocks > 0)
{
if (bhkRigidBodyInterface *irb = (bhkRigidBodyInterface *)node->GetObjectRef()->GetInterface(BHKRIGIDBODYINTERFACE_DESC))
{
int mass = irb->GetMass(0);
float frict = irb->GetFriction(0);
float resti = irb->GetRestitution(0);
int lyr = irb->GetLayer(0);
int msys = irb->GetMotionSystem(0);
int qtype = irb->GetQualityType(0);
float lindamp = irb->GetLinearDamping(0);
float angdamp = irb->GetAngularDamping(0);
float maxlinvel = irb->GetMaxLinearVelocity(0);
float maxangvel = irb->GetMaxAngularVelocity(0);
float pendepth = irb->GetPenetrationDepth(0);
body->SetLayer(OblivionLayer(lyr));
body->SetLayerCopy(OblivionLayer(lyr));
body->SetMotionSystem(MotionSystem(msys));
body->SetQualityType(MotionQuality(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);
}
bhkListShapeRef shape = new bhkListShape();
int mtl = pblock2->GetInt(PB_MATERIAL, 0, 0);
shape->SetMaterial(HavokMaterial(mtl));
vector<bhkShapeRef> shapes;
for (int i = 0; i < nBlocks; i++) {
INode *tnode = NULL;
pblock2->GetValue(PB_MESHLIST,0,tnode,FOREVER,i);
if (tnode != NULL)
{
bhkShapeRef subshape = makeCollisionShape(tnode, tm, body);
if (subshape)
shapes.push_back(subshape);
}
}
shape->SetSubShapes(shapes);
if (shapes.size() == 1) // ignore the list when only one object is present
{
return shapes[0];
}
else if (!shapes.empty())
{
return bhkShapeRef(shape);
}
}
return bhkShapeRef();
}
bhkShapeRef Exporter::makeProxyShape(INode *node, Object *obj, Matrix3& tm)
{
enum { list_params, bv_mesh, }; // pblock2 ID
enum { PB_MATERIAL, PB_MESHLIST, PB_BOUND_TYPE, PB_CENTER, };
enum { bv_type_none, bv_type_box, bv_type_shapes, bv_type_packed, bv_type_convex, }; // pblock ID
bhkShapeRef shape;
if (IParamBlock2* pblock2 = obj->GetParamBlockByID(list_params))
{
int bvType = bv_type_none;
pblock2->GetValue(PB_BOUND_TYPE, 0, bvType, FOREVER, 0);
if (bvType != bv_type_none)
{
if (TriObject *triObj = (TriObject *)obj->ConvertToType(0, triObjectClassID))
{
Mesh& mesh = triObj->GetMesh();
switch (bvType)
{
case bv_type_box:
//case bv_type_sphere:
// shape = makeProxySphereShape(node, obj, mesh, tm);
// break;
bhkShapeRef Exporter::makeProxyBoxShape(INode *node, Object *obj, Mesh& mesh, Matrix3& tm)
{
enum { list_params, bv_mesh, }; // pblock2 ID
enum { PB_MATERIAL, PB_MESHLIST, PB_BOUND_TYPE, PB_CENTER, };
enum { bv_type_none, bv_type_box, bv_type_shapes, bv_type_packed, bv_type_convex, }; // pblock ID
bhkShapeRef retval;
if (IParamBlock2* pblock2 = obj->GetParamBlockByID(list_params))
{
Box3 box; box.Init();
CalcAxisAlignedBox(mesh, box, NULL);
int mtl = 0;
float length = 0, width = 0, height = 0;
pblock2->GetValue(PB_MATERIAL, 0, mtl, FOREVER, 0);
bhkBoxShapeRef shape = new bhkBoxShape();
Vector3 dim(box.Max().x-box.Min().x, box.Max().y-box.Min().y, box.Max().z-box.Min().z);
dim /= (Exporter::bhkScaleFactor * 2);
shape->SetMaterial(HavokMaterial(mtl));
shape->SetDimensions(dim);
Matrix3 ltm = /*GetLocalTM(node) * */TransMatrix(box.Center()) * tm;
if (ltm.IsIdentity())
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
transform->SetShape(shape);
transform->SetMaterial(HavokMaterial(mtl));
retval = StaticCast<bhkShape>(transform);
}
}
return retval;
}
bhkShapeRef Exporter::makeProxySphereShape(INode *node, Object *obj, Mesh& mesh, Matrix3& tm)
{
enum { list_params, bv_mesh, }; // pblock2 ID
enum { PB_MATERIAL, PB_MESHLIST, PB_BOUND_TYPE, PB_CENTER, };
enum { bv_type_none, bv_type_box, bv_type_shapes, bv_type_packed, bv_type_convex, }; // pblock ID
bhkShapeRef shape;
if (IParamBlock2* pblock2 = obj->GetParamBlockByID(list_params))
{
//Matrix3 tm = GetLocalTM(node) * TransMatrix(box.Center());
}
return shape;
}
bhkShapeRef Exporter::makeProxyConvexShape(INode *node, Object *obj, Mesh& mesh, Matrix3& tm)
{
enum { list_params, bv_mesh, }; // pblock2 ID
enum { PB_MATERIAL, PB_MESHLIST, PB_BOUND_TYPE, PB_CENTER, };
enum { bv_type_none, bv_type_box, bv_type_shapes, bv_type_packed, bv_type_convex, }; // pblock ID
bhkShapeRef shape;
if (IParamBlock2* pblock2 = obj->GetParamBlockByID(list_params))
{
if (bhkConvexVerticesShapeRef convShape = makeConvexShape(mesh, tm))
{
int mtl = pblock2->GetInt(PB_MATERIAL, 0, 0);
convShape->SetMaterial(HavokMaterial(mtl));
shape = StaticCast<bhkShape>(convShape);
}
}
return shape;
}
bhkShapeRef Exporter::makeProxyTriStripShape(INode *node, Object *obj, Mesh& mesh, Matrix3& tm)
{
enum { list_params, bv_mesh, }; // pblock2 ID
enum { PB_MATERIAL, PB_MESHLIST, PB_BOUND_TYPE, PB_CENTER, };