forked from mirror/openmw-tes3mp
Create particle systems for NiAutoNormalParticles and NiRotatingParticles nodes
Very incomplete, but it's something to work with.
This commit is contained in:
parent
77ba0fbe73
commit
b5719e0ec7
1 changed files with 163 additions and 8 deletions
|
@ -35,6 +35,8 @@
|
|||
#include <OgreEntity.h>
|
||||
#include <OgreSubEntity.h>
|
||||
#include <OgreTagPoint.h>
|
||||
#include <OgreParticleSystem.h>
|
||||
#include <OgreParticleEmitter.h>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
@ -317,7 +319,9 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro
|
|||
|
||||
if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */
|
||||
node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */
|
||||
node->recType == Nif::RC_NiTriShape /* Handled in the mesh loader */
|
||||
node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */
|
||||
node->recType == Nif::RC_NiAutoNormalParticles ||
|
||||
node->recType == Nif::RC_NiRotatingParticles
|
||||
))
|
||||
warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName());
|
||||
|
||||
|
@ -326,7 +330,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro
|
|||
{
|
||||
if(ctrl->recType == Nif::RC_NiKeyframeController)
|
||||
ctrls.push_back(static_cast<const Nif::NiKeyframeController*>(ctrl.getPtr()));
|
||||
else
|
||||
else if(!(ctrl->recType == Nif::RC_NiParticleSystemController
|
||||
))
|
||||
warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName());
|
||||
ctrl = ctrl->next;
|
||||
}
|
||||
|
@ -588,7 +593,8 @@ static std::string findTextureName(const std::string &filename)
|
|||
}
|
||||
|
||||
public:
|
||||
static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String &name, const Ogre::String &group,
|
||||
static Ogre::String getMaterial(const Nif::ShapeData *shapedata,
|
||||
const Ogre::String &name, const Ogre::String &group,
|
||||
const Nif::NiTexturingProperty *texprop,
|
||||
const Nif::NiMaterialProperty *matprop,
|
||||
const Nif::NiAlphaProperty *alphaprop,
|
||||
|
@ -617,7 +623,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String
|
|||
int specFlags = 0;
|
||||
Ogre::String texName[7];
|
||||
|
||||
bool vertexColour = (shape->data->colors.size() != 0);
|
||||
bool vertexColour = (shapedata->colors.size() != 0);
|
||||
|
||||
// Texture
|
||||
if(texprop)
|
||||
|
@ -819,12 +825,12 @@ class NIFMeshLoader : Ogre::ManualResourceLoader
|
|||
std::string mGroup;
|
||||
size_t mShapeIndex;
|
||||
|
||||
void warn(const std::string &msg)
|
||||
static void warn(const std::string &msg)
|
||||
{
|
||||
std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl;
|
||||
}
|
||||
|
||||
void fail(const std::string &msg)
|
||||
static void fail(const std::string &msg)
|
||||
{
|
||||
std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl;
|
||||
abort();
|
||||
|
@ -1039,9 +1045,10 @@ class NIFMeshLoader : Ogre::ManualResourceLoader
|
|||
}
|
||||
|
||||
bool needTangents=false;
|
||||
std::string matname = NIFMaterialLoader::getMaterial(shape, mesh->getName(), mGroup,
|
||||
std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup,
|
||||
texprop, matprop, alphaprop,
|
||||
vertprop, zprop, specprop, needTangents);
|
||||
vertprop, zprop, specprop,
|
||||
needTangents);
|
||||
if(matname.length() > 0)
|
||||
sub->setMaterialName(matname);
|
||||
|
||||
|
@ -1114,6 +1121,146 @@ class NIFMeshLoader : Ogre::ManualResourceLoader
|
|||
static LoaderMap sLoaders;
|
||||
|
||||
|
||||
static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl)
|
||||
{
|
||||
Ogre::ParticleEmitter *emitter = partsys->addEmitter("Point");
|
||||
emitter->setDirection(Ogre::Vector3::UNIT_Z);
|
||||
emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom,
|
||||
partctrl->velocity+partctrl->velocityRandom);
|
||||
emitter->setEmissionRate(partctrl->emitRate);
|
||||
emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom,
|
||||
partctrl->lifetime+partctrl->lifetimeRandom);
|
||||
|
||||
Nif::ExtraPtr e = partctrl->extra;
|
||||
while(!e.empty())
|
||||
{
|
||||
if(e->recType == Nif::RC_NiParticleGrowFade)
|
||||
{
|
||||
// TODO: Implement
|
||||
}
|
||||
else if(e->recType == Nif::RC_NiParticleColorModifier)
|
||||
{
|
||||
// TODO: Implement (Ogre::ColourInterpolatorAffector?)
|
||||
}
|
||||
else if(e->recType == Nif::RC_NiGravity)
|
||||
{
|
||||
// TODO: Implement (Ogre::LinearForceAffector?)
|
||||
}
|
||||
else
|
||||
warn("Unhandled particle modifier "+e->recName);
|
||||
e = e->extra;
|
||||
}
|
||||
}
|
||||
|
||||
Ogre::ParticleSystem *createParticleSystem(Ogre::SceneManager *sceneMgr, Ogre::Entity *entitybase,
|
||||
const Nif::Node *partnode)
|
||||
{
|
||||
const Nif::NiAutoNormalParticlesData *particledata = NULL;
|
||||
if(partnode->recType == Nif::RC_NiAutoNormalParticles)
|
||||
particledata = static_cast<const Nif::NiAutoNormalParticles*>(partnode)->data.getPtr();
|
||||
else if(partnode->recType == Nif::RC_NiRotatingParticles)
|
||||
particledata = static_cast<const Nif::NiRotatingParticles*>(partnode)->data.getPtr();
|
||||
|
||||
Ogre::ParticleSystem *partsys = sceneMgr->createParticleSystem();
|
||||
try {
|
||||
const Nif::NiTexturingProperty *texprop = NULL;
|
||||
const Nif::NiMaterialProperty *matprop = NULL;
|
||||
const Nif::NiAlphaProperty *alphaprop = NULL;
|
||||
const Nif::NiVertexColorProperty *vertprop = NULL;
|
||||
const Nif::NiZBufferProperty *zprop = NULL;
|
||||
const Nif::NiSpecularProperty *specprop = NULL;
|
||||
if(partnode->parent)
|
||||
{
|
||||
// FIXME: We should probably search down the whole tree instead of just the parent
|
||||
const Nif::PropertyList &proplist = partnode->parent->props;
|
||||
for(size_t i = 0;i < proplist.length();i++)
|
||||
{
|
||||
// Entries may be empty
|
||||
if(proplist[i].empty())
|
||||
continue;
|
||||
|
||||
const Nif::Property *pr = proplist[i].getPtr();
|
||||
if(pr->recType == Nif::RC_NiTexturingProperty)
|
||||
texprop = static_cast<const Nif::NiTexturingProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiMaterialProperty)
|
||||
matprop = static_cast<const Nif::NiMaterialProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiAlphaProperty)
|
||||
alphaprop = static_cast<const Nif::NiAlphaProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiVertexColorProperty)
|
||||
vertprop = static_cast<const Nif::NiVertexColorProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiZBufferProperty)
|
||||
zprop = static_cast<const Nif::NiZBufferProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiSpecularProperty)
|
||||
specprop = static_cast<const Nif::NiSpecularProperty*>(pr);
|
||||
else
|
||||
warn("Unhandled property type: "+pr->recName);
|
||||
}
|
||||
}
|
||||
const Nif::PropertyList &proplist = partnode->props;
|
||||
for(size_t i = 0;i < proplist.length();i++)
|
||||
{
|
||||
// Entries may be empty
|
||||
if(proplist[i].empty())
|
||||
continue;
|
||||
|
||||
const Nif::Property *pr = proplist[i].getPtr();
|
||||
if(pr->recType == Nif::RC_NiTexturingProperty)
|
||||
texprop = static_cast<const Nif::NiTexturingProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiMaterialProperty)
|
||||
matprop = static_cast<const Nif::NiMaterialProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiAlphaProperty)
|
||||
alphaprop = static_cast<const Nif::NiAlphaProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiVertexColorProperty)
|
||||
vertprop = static_cast<const Nif::NiVertexColorProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiZBufferProperty)
|
||||
zprop = static_cast<const Nif::NiZBufferProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiSpecularProperty)
|
||||
specprop = static_cast<const Nif::NiSpecularProperty*>(pr);
|
||||
else
|
||||
warn("Unhandled property type: "+pr->recName);
|
||||
}
|
||||
|
||||
std::string fullname = mName+"@index="+Ogre::StringConverter::toString(partnode->recIndex);
|
||||
if(partnode->name.length() > 0)
|
||||
fullname += "@type="+partnode->name;
|
||||
Misc::StringUtils::toLower(fullname);
|
||||
|
||||
bool needTangents;
|
||||
partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, mGroup,
|
||||
texprop, matprop, alphaprop,
|
||||
vertprop, zprop, specprop,
|
||||
needTangents));
|
||||
|
||||
partsys->setDefaultDimensions(particledata->particleSize, particledata->particleSize);
|
||||
partsys->setCullIndividually(false);
|
||||
partsys->setParticleQuota(particledata->activeCount);
|
||||
|
||||
Nif::ControllerPtr ctrl = partnode->controller;
|
||||
while(!ctrl.empty())
|
||||
{
|
||||
if(ctrl->recType == Nif::RC_NiParticleSystemController)
|
||||
{
|
||||
const Nif::NiParticleSystemController *partctrl = static_cast<const Nif::NiParticleSystemController*>(ctrl.getPtr());
|
||||
|
||||
createParticleEmitterAffectors(partsys, partctrl);
|
||||
if(!partctrl->emitter.empty() && !partsys->isAttached())
|
||||
entitybase->attachObjectToBone(partctrl->emitter->name, partsys);
|
||||
}
|
||||
ctrl = ctrl->next;
|
||||
}
|
||||
|
||||
if(!partsys->isAttached())
|
||||
entitybase->attachObjectToBone(partnode->name, partsys);
|
||||
}
|
||||
catch(std::exception &e) {
|
||||
std::cerr<< "Particles exception: "<<e.what() <<std::endl;
|
||||
sceneMgr->destroyParticleSystem(partsys);
|
||||
partsys = NULL;
|
||||
};
|
||||
return partsys;
|
||||
}
|
||||
|
||||
|
||||
NIFMeshLoader(const std::string &name, const std::string &group)
|
||||
: mName(name), mGroup(group), mShapeIndex(~(size_t)0)
|
||||
{ }
|
||||
|
@ -1199,6 +1346,14 @@ class NIFMeshLoader : Ogre::ManualResourceLoader
|
|||
}
|
||||
}
|
||||
|
||||
if((node->recType == Nif::RC_NiAutoNormalParticles ||
|
||||
node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x01))
|
||||
{
|
||||
Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, entities.mSkelBase, node);
|
||||
if(partsys != NULL)
|
||||
entities.mParticles.push_back(partsys);
|
||||
}
|
||||
|
||||
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(node);
|
||||
if(ninode)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue