From 018115601af6f9149d48c73ecc90a80d86ca4d0b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Mar 2015 16:49:33 +0100 Subject: [PATCH] Move particle emitter/affector handling to separate functions --- components/nifosg/nifloader.cpp | 113 +++++++++++++++++--------------- 1 file changed, 61 insertions(+), 52 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 60e94c67a..b41bc075f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -442,12 +442,13 @@ namespace NifOsg for (size_t i = 0; i mSource = boost::shared_ptr(new FrameTimeSource); @@ -455,7 +456,6 @@ namespace NifOsg toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); } - osg::ref_ptr handleNode(const Nif::Node* nifNode, bool createSkeleton, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { @@ -623,7 +623,6 @@ namespace NifOsg } } - void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) @@ -651,7 +650,6 @@ namespace NifOsg } } - void handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) @@ -724,11 +722,14 @@ namespace NifOsg } } - - void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) + // Load the initial state of the particle system, i.e. the initial particles and their positions, velocity and colors. + void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl, + osgParticle::ParticleProcessor::ReferenceFrame rf) { - osg::ref_ptr partsys (new ParticleSystem); - partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); + // TODO: also take into account the transform by placement in the scene (should be done post-load) + osg::Matrix particletransform; + if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) + particletransform = getWorldTransform(nifNode); const Nif::NiAutoNormalParticlesData *particledata = NULL; if(nifNode->recType == Nif::RC_NiAutoNormalParticles) @@ -738,35 +739,6 @@ namespace NifOsg else return; - const Nif::NiParticleSystemController* partctrl = NULL; - for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) - { - if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) - continue; - if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) - partctrl = static_cast(ctrl.getPtr()); - } - if (!partctrl) - { - std::cerr << "No particle controller found " << std::endl; - return; - } - - std::vector targets; - if (partctrl->recType == Nif::RC_NiBSPArrayController) - { - getAllNiNodes(partctrl->emitter.getPtr(), targets); - } - - osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) - ? osgParticle::ParticleProcessor::RELATIVE_RF - : osgParticle::ParticleProcessor::ABSOLUTE_RF; - - // TODO: also take into account the transform by placement in the scene - osg::Matrix particletransform; - if (rf == osgParticle::ParticleProcessor::ABSOLUTE_RF) - particletransform = getWorldTransform(nifNode); - int i=0; for (std::vector::const_iterator it = partctrl->particles.begin(); iactiveCount && it != partctrl->particles.end(); ++it, ++i) @@ -789,18 +761,17 @@ namespace NifOsg created->setSizeRange(osgParticle::rangef(size, size)); } + } - partsys->setQuota(partctrl->numParticles); - - partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); - partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); - partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); - - // ---- emitter + osg::ref_ptr handleParticleEmitter(const Nif::NiParticleSystemController* partctrl) + { + std::vector targets; + if (partctrl->recType == Nif::RC_NiBSPArrayController) + { + getAllNiNodes(partctrl->emitter.getPtr(), targets); + } osg::ref_ptr emitter = new Emitter(targets); - emitter->setParticleSystem(partsys); - emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); osgParticle::ConstantRateCounter* counter = new osgParticle::ConstantRateCounter; if (partctrl->emitFlags & Nif::NiParticleSystemController::NoAutoAdjust) @@ -823,6 +794,43 @@ namespace NifOsg placer->setZRange(-partctrl->offsetRandom.z(), partctrl->offsetRandom.z()); emitter->setPlacer(placer); + return emitter; + } + + void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode) + { + osg::ref_ptr partsys (new ParticleSystem); + partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); + + const Nif::NiParticleSystemController* partctrl = NULL; + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) + partctrl = static_cast(ctrl.getPtr()); + } + if (!partctrl) + { + std::cerr << "No particle controller found " << std::endl; + return; + } + + osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace) + ? osgParticle::ParticleProcessor::RELATIVE_RF + : osgParticle::ParticleProcessor::ABSOLUTE_RF; + + handleParticleInitialState(nifNode, partsys, partctrl, rf); + + partsys->setQuota(partctrl->numParticles); + + partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); + partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(osg::Vec4f(1.f,1.f,1.f,1.f), osg::Vec4f(1.f,1.f,1.f,1.f))); + partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); + + osg::ref_ptr emitter = handleParticleEmitter(partctrl); + emitter->setParticleSystem(partsys); + emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. @@ -859,6 +867,11 @@ namespace NifOsg partsys->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + // particle system updater (after the emitters and affectors in the scene graph) + // I think for correct culling needs to be *before* the ParticleSystem, though osg examples do it the other way + osg::ref_ptr updater = new osgParticle::ParticleSystemUpdater; + updater->addParticleSystem(partsys); + parentNode->addChild(updater); if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) parentNode->addChild(geode); @@ -869,11 +882,6 @@ namespace NifOsg trans->addChild(geode); parentNode->addChild(trans); } - - // particle system updater (after the emitters and affectors in the scene graph) - osgParticle::ParticleSystemUpdater* updater = new osgParticle::ParticleSystemUpdater; - updater->addParticleSystem(partsys); - parentNode->addChild(updater); } void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) @@ -1061,7 +1069,7 @@ namespace NifOsg } - void handleProperty(const Nif::Property *property, const Nif::Node* nifNode, + void handleProperty(const Nif::Property *property, osg::Node *node, std::map& boundTextures, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1088,6 +1096,7 @@ namespace NifOsg stateset->setMode(GL_CULL_FACE, stencilprop->data.drawMode == 3 ? osg::StateAttribute::OFF : osg::StateAttribute::ON); + // TODO: // Stencil settings not enabled yet, not sure if the original engine is actually using them, // since they might conflict with Morrowind's stencil shadows. /*