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
enum
{
CAPSULE_RADIUS = 0,
CAPSULE_HEIGHT = 1,
};
class HavokMoppCode
{
private:
typedef int (__stdcall * fnGenerateMoppCode)(int nVerts, Vector3 const* verts, int nTris, Triangle const *tris);
typedef int (__stdcall * fnRetrieveMoppCode)(int nBuffer, unsigned char *buffer);
typedef int (__stdcall * fnRetrieveMoppScale)(float *value);
typedef int (__stdcall * fnRetrieveMoppOrigin)(Vector3 *value);
HMODULE hMoppLib;
fnGenerateMoppCode GenerateMoppCode;
fnRetrieveMoppCode RetrieveMoppCode;
fnRetrieveMoppScale RetrieveMoppScale;
fnRetrieveMoppOrigin RetrieveMoppOrigin;
public:
HavokMoppCode() : hMoppLib(0), GenerateMoppCode(0), RetrieveMoppCode(0), RetrieveMoppScale(0), RetrieveMoppOrigin(0) {
}
Gundalf
committed
~HavokMoppCode() {
if (hMoppLib) FreeLibrary(hMoppLib);
}
bool Initialize()
{
if (hMoppLib == NULL)
{
hMoppLib = LoadLibraryA( "NifMopp.dll" );
GenerateMoppCode = (fnGenerateMoppCode)GetProcAddress( hMoppLib, "GenerateMoppCode" );
RetrieveMoppCode = (fnRetrieveMoppCode)GetProcAddress( hMoppLib, "RetrieveMoppCode" );
RetrieveMoppScale = (fnRetrieveMoppScale)GetProcAddress( hMoppLib, "RetrieveMoppScale" );
RetrieveMoppOrigin = (fnRetrieveMoppOrigin)GetProcAddress( hMoppLib, "RetrieveMoppOrigin" );
}
return ( NULL != GenerateMoppCode && NULL != RetrieveMoppCode
&& NULL != RetrieveMoppScale && NULL != RetrieveMoppOrigin
);
vector<Niflib::byte> CalculateMoppCode( vector<Niflib::Vector3> const & verts, vector<Niflib::Triangle> const & tris, Niflib::Vector3* origin, float* scale)
{
vector<Niflib::byte> code;
if ( Initialize() )
{
int len = GenerateMoppCode( verts.size(), &verts[0], tris.size(), &tris[0] );
if ( len > 0 )
{
code.resize( len );
if ( 0 != RetrieveMoppCode( len , &code[0] ) )
{
if ( NULL != scale )
RetrieveMoppScale(scale);
if ( NULL != origin )
RetrieveMoppOrigin(origin);
}
else
{
code.clear();
}
}
}
return code;
} TheHavokCode;
static vector<Niflib::byte> ConstructHKMesh( NiTriBasedGeomRef shape, Niflib::Vector3& origin, float& scale)
return TheHavokCode.CalculateMoppCode(data->GetVertices(), data->GetTriangles(), &origin, &scale);
static vector<Niflib::byte> ConstructHKMesh( bhkPackedNiTriStripsShapeRef shape, Niflib::Vector3& origin, float& scale)
return TheHavokCode.CalculateMoppCode(data->GetVertices(), data->GetTriangles(), &origin, &scale);
Gundalf
committed
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*
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)
{
{
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) || (node->IsHidden() && !mExportHidden))
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);
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
{
// 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;
}
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
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);
static bhkMoppBvTreeShapeRef makeTreeShape(bhkPackedNiTriStripsShapeRef mesh)
{
bhkMoppBvTreeShapeRef mopp = new bhkMoppBvTreeShape();
mopp->SetMaterial( HAV_MAT_WOOD );
mopp->SetShape( mesh );
try
{
Niflib::Vector3 offset;
float scale;
vector<Niflib::byte> moppcode = ConstructHKMesh(mesh, offset, scale);
mopp->SetMoppOrigin( offset );
mopp->SetMoppScale( scale );
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
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] = (USHORT)face.getVert(0);
tri[1] = (USHORT)face.getVert(1);
tri[2] = (USHORT)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);
OblivionSubShape subshape;
subshape.layer = OL_STATIC;
subshape.material = HAV_MAT_WOOD;
subshape.numVertices = verts.size();
vector<OblivionSubShape> subshapes;
subshapes.push_back(subshape);
shape->SetSubShapes( subshapes );
//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);
Tazpn
committed
CalcCenteredSphere(mesh, center, radius);
radius /= Exporter::bhkScaleFactor;
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;
Tazpn
committed
value[3] = -(mesh.FaceCenter(i) * tm).Length() / Exporter::bhkScaleFactor;
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
{
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
{
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);
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]);
float radius = max( max(dim.x, dim.y), dim.z );
box->SetRadius(radius);
// 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 (node == NULL || (node->IsHidden() && !mExportHidden))
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 && (!tnode->IsHidden() || mExportHidden)) {
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());
}
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))
{
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
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 && (!tnode->IsHidden() || mExportHidden))
{
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))
{