// Populate the particles list
void ParticlesChooser::populateParticleList()
{
	_iterMap.clear();
	_particlesList->clear();

	// Create and use a ParticlesVisitor to populate the list
	ParticlesVisitor visitor(_particlesList, _iterMap);
	GlobalParticlesManager().forEachParticleDef(visitor);
}
	// The worker function that will execute in the thread
    void run()
    {
        ScopedDebugTimer timer("ThreadedParticlesLoader::run()");

		// Create and use a ParticlesVisitor to populate the list
		GlobalParticlesManager().forEachParticleDef(*this);

		wxutil::TreeModel::PopulationFinishedEvent finishedEvent;
		finishedEvent.SetTreeModel(_store);

		_finishedHandler->AddPendingEvent(finishedEvent);
    }
// Static instance owner
ParticlesChooser& ParticlesChooser::getInstance()
{
	ParticlesChooserPtr& instancePtr = getInstancePtr();

	if (!instancePtr)
	{
		instancePtr.reset(new ParticlesChooser);

		GlobalRadiant().signal_radiantShutdown().connect(
            sigc::mem_fun(*instancePtr, &ParticlesChooser::onRadiantShutdown)
        );
		GlobalParticlesManager().signal_particlesReloaded().connect(
            sigc::mem_fun(*instancePtr, &ParticlesChooser::reloadParticles)
        );
	}

	return *instancePtr;
}
scene::INodePtr ModelCache::getModelNode(const std::string& modelPath)
{
	// Check if we have a reference to a modeldef
	IModelDefPtr modelDef = GlobalEntityClassManager().findModel(modelPath);

	// The actual model path (is usually the same as the incoming modelPath)
	std::string actualModelPath(modelPath);

	if (modelDef != NULL)
	{
		// We have a valid modelDef, override the model path
		actualModelPath = modelDef->mesh;
	}

	// Get the extension of this model
	std::string type = actualModelPath.substr(actualModelPath.rfind(".") + 1);

	if (type == "prt")
	{
		// This is a particle, pass the call to the Particles Manager
		return GlobalParticlesManager().createParticleNode(actualModelPath);
	}

	// Get a suitable model loader
	ModelLoaderPtr modelLoader = getModelLoaderForType(type);

	// Try to construct a model node using the suitable loader
	scene::INodePtr node = modelLoader->loadModel(actualModelPath);

	if (node)
	{
		// For MD5 models, apply the idle animation by default
		if (modelDef)
		{
			model::ModelNodePtr modelNode = Node_getModel(node);

			if (!modelNode)
			{
				return node;
			}

			// Set the animation to play
			try
			{
				md5::IMD5Model& md5model = dynamic_cast<md5::IMD5Model&>(modelNode->getIModel());

				// Look up the "idle" anim if there is one
				IModelDef::Anims::const_iterator found = modelDef->anims.find("idle");

				if (found != modelDef->anims.end())
				{
					// Load the anim
					md5::IMD5AnimPtr anim = GlobalAnimationCache().getAnim(found->second);

					if (anim)
					{
						md5model.setAnim(anim);
						md5model.updateAnim(0);
					}
				}
			}
			catch (std::bad_cast&)
			{
				// not an MD5 model, do nothing
			}
		}

		// Model load was successful
		return node;
	}

	// The model load failed, let's return the NullModel
	// This call should never fail, i.e. the returned model is non-NULL
	return NullModelLoader::InstancePtr()->loadModel(actualModelPath);
}
void ParticlePreview::setParticle(const std::string& name)
{
    std::string nameClean = name;

    if (boost::algorithm::ends_with(nameClean, ".prt"))
    {
        nameClean = nameClean.substr(0, nameClean.length() - 4);
    }

    // If the model name is empty, release the model
    if (nameClean.empty())
    {
        if (_particleNode)
        {
            _entity->removeChildNode(_particleNode);
        }

        _particleNode.reset();
        stopPlayback();
        return;
    }

    // Set up the scene
    if (!_entity)
    {
        setupSceneGraph();
    }

    if (_particleNode)
    {
        _entity->removeChildNode(_particleNode);
    }

    // Construct the particle emitter node
    _particleNode = GlobalParticlesManager().createParticleNode(nameClean);

    if (_particleNode && _lastParticle != nameClean)
    {
        _entity->addChildNode(_particleNode);

        // Reset preview time
        stopPlayback();

        // Reset the rotation to the default one
        _rotation = Matrix4::getRotation(Vector3(0,-1,0), Vector3(0,-0.3f,1));
        _rotation.multiplyBy(Matrix4::getRotation(Vector3(0,1,0), Vector3(1,-1,0)));

        // Call update(0) once to enable the bounds calculation
        _particleNode->getParticle()->update(_rotation);

        // Use particle AABB to adjust camera distance
        const AABB& particleBounds = _particleNode->getParticle()->getBounds();

        if (particleBounds.isValid())
        {
            _camDist = -2.0f * static_cast<float>(particleBounds.getRadius());
        }
        else
        {
            // Bounds not valid, fall back to default
            _camDist = -40.0f;
        }

        _lastParticle = nameClean;

        // Start playback when switching particles
        startPlayback();
    }

    // Redraw
    queueDraw();
}