|
|
|
@ -452,6 +452,7 @@ namespace NifOsg
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case Nif::RC_NiTriShape:
|
|
|
|
|
case Nif::RC_NiTriStrips:
|
|
|
|
|
case Nif::RC_NiAutoNormalParticles:
|
|
|
|
|
case Nif::RC_NiRotatingParticles:
|
|
|
|
|
// Leaf nodes in the NIF hierarchy, so won't be able to dynamically attach children.
|
|
|
|
@ -575,7 +576,7 @@ namespace NifOsg
|
|
|
|
|
node->setDataVariance(osg::Object::DYNAMIC);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nifNode->recType == Nif::RC_NiTriShape && isAnimated) // the same thing for animated NiTriShapes
|
|
|
|
|
if ((nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips) && isAnimated) // Same thing for animated shapes
|
|
|
|
|
{
|
|
|
|
|
node->setDataVariance(osg::Object::DYNAMIC);
|
|
|
|
|
}
|
|
|
|
@ -584,20 +585,25 @@ namespace NifOsg
|
|
|
|
|
|
|
|
|
|
applyNodeProperties(nifNode, node, composite, imageManager, boundTextures, animflags);
|
|
|
|
|
|
|
|
|
|
if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes)
|
|
|
|
|
if ((nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips) && !skipMeshes)
|
|
|
|
|
{
|
|
|
|
|
const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(nifNode);
|
|
|
|
|
const std::string nodeName = Misc::StringUtils::lowerCase(triShape->name);
|
|
|
|
|
const std::string nodeName = Misc::StringUtils::lowerCase(nifNode->name);
|
|
|
|
|
static const std::string markerName = "tri editormarker";
|
|
|
|
|
static const std::string shadowName = "shadow";
|
|
|
|
|
static const std::string shadowName2 = "tri shadow";
|
|
|
|
|
const bool isMarker = hasMarkers && !nodeName.compare(0, markerName.size(), markerName);
|
|
|
|
|
if (!isMarker && nodeName.compare(0, shadowName.size(), shadowName) && nodeName.compare(0, shadowName2.size(), shadowName2))
|
|
|
|
|
{
|
|
|
|
|
if (triShape->skin.empty())
|
|
|
|
|
handleTriShape(triShape, node, composite, boundTextures, animflags);
|
|
|
|
|
Nif::NiSkinInstancePtr skin;
|
|
|
|
|
if (nifNode->recType == Nif::RC_NiTriShape)
|
|
|
|
|
skin = static_cast<const Nif::NiTriShape*>(nifNode)->skin;
|
|
|
|
|
else // if (nifNode->recType == Nif::RC_NiTriStrips)
|
|
|
|
|
skin = static_cast<const Nif::NiTriStrips*>(nifNode)->skin;
|
|
|
|
|
|
|
|
|
|
if (skin.empty())
|
|
|
|
|
handleTriShape(nifNode, node, composite, boundTextures, animflags);
|
|
|
|
|
else
|
|
|
|
|
handleSkinnedTriShape(triShape, node, composite, boundTextures, animflags);
|
|
|
|
|
handleSkinnedTriShape(nifNode, node, composite, boundTextures, animflags);
|
|
|
|
|
|
|
|
|
|
if (!nifNode->controller.empty())
|
|
|
|
|
handleMeshControllers(nifNode, node, composite, boundTextures, animflags);
|
|
|
|
@ -612,7 +618,8 @@ namespace NifOsg
|
|
|
|
|
|
|
|
|
|
// Note: NiTriShapes are not allowed to have KeyframeControllers (the vanilla engine just crashes when there is one).
|
|
|
|
|
// We can take advantage of this constraint for optimizations later.
|
|
|
|
|
if (nifNode->recType != Nif::RC_NiTriShape && !nifNode->controller.empty() && node->getDataVariance() == osg::Object::DYNAMIC)
|
|
|
|
|
if (nifNode->recType != Nif::RC_NiTriShape && nifNode->recType != Nif::RC_NiTriStrips
|
|
|
|
|
&& !nifNode->controller.empty() && node->getDataVariance() == osg::Object::DYNAMIC)
|
|
|
|
|
handleNodeControllers(nifNode, static_cast<osg::MatrixTransform*>(node.get()), animflags);
|
|
|
|
|
|
|
|
|
|
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(nifNode);
|
|
|
|
@ -673,7 +680,7 @@ namespace NifOsg
|
|
|
|
|
handleVisController(static_cast<const Nif::NiVisController*>(ctrl.getPtr()), node, animflags);
|
|
|
|
|
}
|
|
|
|
|
else if(ctrl->recType == Nif::RC_NiGeomMorpherController)
|
|
|
|
|
{} // handled in handleTriShape
|
|
|
|
|
{} // handled in handleMorphController
|
|
|
|
|
else
|
|
|
|
|
Log(Debug::Info) << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename;
|
|
|
|
|
}
|
|
|
|
@ -1030,57 +1037,100 @@ namespace NifOsg
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
|
|
|
|
|
void triCommonToGeometry(osg::Geometry *geometry, const std::vector<osg::Vec3f>& vertices, const std::vector<osg::Vec3f>& normals, const std::vector<std::vector<osg::Vec2f>>& uvlist, const std::vector<osg::Vec4f>& colors, const std::vector<int>& boundTextures, const std::string& name)
|
|
|
|
|
{
|
|
|
|
|
const Nif::NiTriShapeData* data = triShape->data.getPtr();
|
|
|
|
|
|
|
|
|
|
if (!data->vertices.empty())
|
|
|
|
|
geometry->setVertexArray(new osg::Vec3Array(data->vertices.size(), data->vertices.data()));
|
|
|
|
|
if (!data->normals.empty())
|
|
|
|
|
geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), data->normals.data()), osg::Array::BIND_PER_VERTEX);
|
|
|
|
|
if (!vertices.empty())
|
|
|
|
|
geometry->setVertexArray(new osg::Vec3Array(vertices.size(), vertices.data()));
|
|
|
|
|
if (!normals.empty())
|
|
|
|
|
geometry->setNormalArray(new osg::Vec3Array(normals.size(), normals.data()), osg::Array::BIND_PER_VERTEX);
|
|
|
|
|
if (!colors.empty())
|
|
|
|
|
geometry->setColorArray(new osg::Vec4Array(colors.size(), colors.data()), osg::Array::BIND_PER_VERTEX);
|
|
|
|
|
|
|
|
|
|
int textureStage = 0;
|
|
|
|
|
for (std::vector<int>::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it,++textureStage)
|
|
|
|
|
for (const int uvSet : boundTextures)
|
|
|
|
|
{
|
|
|
|
|
int uvSet = *it;
|
|
|
|
|
if (uvSet >= (int)data->uvlist.size())
|
|
|
|
|
if (uvSet >= (int)uvlist.size())
|
|
|
|
|
{
|
|
|
|
|
Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on TriShape \"" << triShape->name << "\" in " << mFilename;
|
|
|
|
|
if (!data->uvlist.empty())
|
|
|
|
|
geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[0].size(), data->uvlist[0].data()), osg::Array::BIND_PER_VERTEX);
|
|
|
|
|
Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on shape \"" << name << "\" in " << mFilename;
|
|
|
|
|
if (!uvlist.empty())
|
|
|
|
|
geometry->setTexCoordArray(textureStage, new osg::Vec2Array(uvlist[0].size(), uvlist[0].data()), osg::Array::BIND_PER_VERTEX);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), data->uvlist[uvSet].data()), osg::Array::BIND_PER_VERTEX);
|
|
|
|
|
geometry->setTexCoordArray(textureStage, new osg::Vec2Array(uvlist[uvSet].size(), uvlist[uvSet].data()), osg::Array::BIND_PER_VERTEX);
|
|
|
|
|
textureStage++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!data->colors.empty())
|
|
|
|
|
geometry->setColorArray(new osg::Vec4Array(data->colors.size(), data->colors.data()), osg::Array::BIND_PER_VERTEX);
|
|
|
|
|
|
|
|
|
|
void triShapeToGeometry(const Nif::Node *nifNode, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
|
|
|
|
|
{
|
|
|
|
|
bool vertexColorsPresent = false;
|
|
|
|
|
if (nifNode->recType == Nif::RC_NiTriShape)
|
|
|
|
|
{
|
|
|
|
|
const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(nifNode);
|
|
|
|
|
const Nif::NiTriShapeData* data = triShape->data.getPtr();
|
|
|
|
|
vertexColorsPresent = !data->colors.empty();
|
|
|
|
|
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triShape->name);
|
|
|
|
|
if (!data->triangles.empty())
|
|
|
|
|
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES,
|
|
|
|
|
data->triangles.size(),
|
|
|
|
|
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(),
|
|
|
|
|
(unsigned short*)data->triangles.data()));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const Nif::NiTriStrips* triStrips = static_cast<const Nif::NiTriStrips*>(nifNode);
|
|
|
|
|
const Nif::NiTriStripsData* data = triStrips->data.getPtr();
|
|
|
|
|
vertexColorsPresent = !data->colors.empty();
|
|
|
|
|
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triStrips->name);
|
|
|
|
|
if (!data->strips.empty())
|
|
|
|
|
{
|
|
|
|
|
for (const std::vector<unsigned short>& strip : data->strips)
|
|
|
|
|
{
|
|
|
|
|
// Can't make a triangle from less than three vertices.
|
|
|
|
|
if (strip.size() < 3)
|
|
|
|
|
continue;
|
|
|
|
|
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(),
|
|
|
|
|
(unsigned short*)strip.data()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// osg::Material properties are handled here for two reasons:
|
|
|
|
|
// - if there are no vertex colors, we need to disable colorMode.
|
|
|
|
|
// - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them
|
|
|
|
|
// above the actual renderable would be tedious.
|
|
|
|
|
std::vector<const Nif::Property*> drawableProps;
|
|
|
|
|
collectDrawableProperties(triShape, drawableProps);
|
|
|
|
|
applyDrawableProperties(parentNode, drawableProps, composite, !data->colors.empty(), animflags, false);
|
|
|
|
|
collectDrawableProperties(nifNode, drawableProps);
|
|
|
|
|
applyDrawableProperties(parentNode, drawableProps, composite, vertexColorsPresent, animflags, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
|
|
|
|
|
void handleTriShape(const Nif::Node* nifNode, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
|
|
|
|
|
{
|
|
|
|
|
assert(nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips);
|
|
|
|
|
osg::ref_ptr<osg::Drawable> drawable;
|
|
|
|
|
for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next)
|
|
|
|
|
osg::ref_ptr<osg::Geometry> geom (new osg::Geometry);
|
|
|
|
|
triShapeToGeometry(nifNode, geom, parentNode, composite, boundTextures, animflags);
|
|
|
|
|
Nif::ControllerPtr ctrl;
|
|
|
|
|
if (nifNode->recType == Nif::RC_NiTriShape)
|
|
|
|
|
ctrl = static_cast<const Nif::NiTriShape*>(nifNode)->controller;
|
|
|
|
|
else
|
|
|
|
|
ctrl = static_cast<const Nif::NiTriStrips*>(nifNode)->controller;
|
|
|
|
|
handleMorphController(ctrl, drawable, geom, parentNode, composite, boundTextures, animflags);
|
|
|
|
|
|
|
|
|
|
if (!drawable.get())
|
|
|
|
|
drawable = geom;
|
|
|
|
|
drawable->setName(nifNode->name);
|
|
|
|
|
parentNode->addChild(drawable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handleMorphController(Nif::ControllerPtr ctrl, osg::Drawable *drawable, osg::ref_ptr<osg::Geometry> geom, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
|
|
|
|
|
{
|
|
|
|
|
for (; !ctrl.empty(); ctrl = ctrl->next)
|
|
|
|
|
{
|
|
|
|
|
if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active))
|
|
|
|
|
continue;
|
|
|
|
|
if(ctrl->recType == Nif::RC_NiGeomMorpherController)
|
|
|
|
|
{
|
|
|
|
|
drawable = handleMorphGeometry(static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr()), triShape, parentNode, composite, boundTextures, animflags);
|
|
|
|
|
drawable = handleMorphGeometry(static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr()), geom, parentNode, composite, boundTextures, animflags);
|
|
|
|
|
|
|
|
|
|
osg::ref_ptr<GeomMorpherController> morphctrl = new GeomMorpherController(
|
|
|
|
|
static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr())->data.getPtr());
|
|
|
|
@ -1089,25 +1139,11 @@ namespace NifOsg
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!drawable.get())
|
|
|
|
|
{
|
|
|
|
|
osg::ref_ptr<osg::Geometry> geom (new osg::Geometry);
|
|
|
|
|
drawable = geom;
|
|
|
|
|
triShapeToGeometry(triShape, geom, parentNode, composite, boundTextures, animflags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
drawable->setName(triShape->name);
|
|
|
|
|
|
|
|
|
|
parentNode->addChild(drawable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
osg::ref_ptr<osg::Drawable> handleMorphGeometry(const Nif::NiGeomMorpherController* morpher, const Nif::NiTriShape *triShape, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
|
|
|
|
|
osg::ref_ptr<osg::Drawable> handleMorphGeometry(const Nif::NiGeomMorpherController* morpher, osg::ref_ptr<osg::Geometry> sourceGeometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
|
|
|
|
|
{
|
|
|
|
|
osg::ref_ptr<SceneUtil::MorphGeometry> morphGeom = new SceneUtil::MorphGeometry;
|
|
|
|
|
|
|
|
|
|
osg::ref_ptr<osg::Geometry> sourceGeometry (new osg::Geometry);
|
|
|
|
|
triShapeToGeometry(triShape, sourceGeometry, parentNode, composite, boundTextures, animflags);
|
|
|
|
|
morphGeom->setSourceGeometry(sourceGeometry);
|
|
|
|
|
|
|
|
|
|
const std::vector<Nif::NiMorphData::MorphData>& morphs = morpher->data.getPtr()->mMorphs;
|
|
|
|
@ -1120,21 +1156,25 @@ namespace NifOsg
|
|
|
|
|
return morphGeom;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite,
|
|
|
|
|
void handleSkinnedTriShape(const Nif::Node *nifNode, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite,
|
|
|
|
|
const std::vector<int>& boundTextures, int animflags)
|
|
|
|
|
{
|
|
|
|
|
assert(nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips);
|
|
|
|
|
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
|
|
|
|
|
triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags);
|
|
|
|
|
|
|
|
|
|
triShapeToGeometry(nifNode, geometry, parentNode, composite, boundTextures, animflags);
|
|
|
|
|
osg::ref_ptr<SceneUtil::RigGeometry> rig(new SceneUtil::RigGeometry);
|
|
|
|
|
rig->setSourceGeometry(geometry);
|
|
|
|
|
rig->setName(triShape->name);
|
|
|
|
|
|
|
|
|
|
const Nif::NiSkinInstance *skin = triShape->skin.getPtr();
|
|
|
|
|
rig->setName(nifNode->name);
|
|
|
|
|
|
|
|
|
|
// Assign bone weights
|
|
|
|
|
osg::ref_ptr<SceneUtil::RigGeometry::InfluenceMap> map (new SceneUtil::RigGeometry::InfluenceMap);
|
|
|
|
|
|
|
|
|
|
Nif::NiSkinInstancePtr skinPtr;
|
|
|
|
|
if (nifNode->recType == Nif::RC_NiTriShape)
|
|
|
|
|
skinPtr = static_cast<const Nif::NiTriShape*>(nifNode)->skin;
|
|
|
|
|
else
|
|
|
|
|
skinPtr = static_cast<const Nif::NiTriStrips*>(nifNode)->skin;
|
|
|
|
|
const Nif::NiSkinInstance *skin = skinPtr.getPtr();
|
|
|
|
|
const Nif::NiSkinData *data = skin->data.getPtr();
|
|
|
|
|
const Nif::NodeList &bones = skin->bones;
|
|
|
|
|
for(size_t i = 0;i < bones.length();i++)
|
|
|
|
|