mirror of
				https://github.com/TES3MP/openmw-tes3mp.git
				synced 2025-10-29 03:26:42 +00:00 
			
		
		
		
	Delete the old nifogre loader
This commit is contained in:
		
							parent
							
								
									376f0f3ac1
								
							
						
					
					
						commit
						1affa497d5
					
				
					 14 changed files with 0 additions and 3817 deletions
				
			
		|  | @ -50,10 +50,6 @@ add_component_dir (nifosg | |||
| #    nifcache | ||||
| #    ) | ||||
| 
 | ||||
| #add_component_dir (nifogre | ||||
| #    ogrenifloader skeleton material mesh particles controller | ||||
| #    ) | ||||
| 
 | ||||
| #add_component_dir (nifbullet | ||||
| #    bulletnifloader | ||||
| #    ) | ||||
|  |  | |||
|  | @ -1,111 +0,0 @@ | |||
| #ifndef COMPONENTS_NIFOGRE_CONTROLLER_H | ||||
| #define COMPONENTS_NIFOGRE_CONTROLLER_H | ||||
| 
 | ||||
| #include <components/nif/niffile.hpp> | ||||
| #include <components/nif/nifkey.hpp> | ||||
| #include <OgreController.h> | ||||
| 
 | ||||
| namespace NifOgre | ||||
| { | ||||
| 
 | ||||
|     class ValueInterpolator | ||||
|     { | ||||
|     protected: | ||||
|         float interpKey(const Nif::FloatKeyMap::MapType &keys, float time, float def=0.f) const | ||||
|         { | ||||
|             if (keys.size() == 0) | ||||
|                 return def; | ||||
| 
 | ||||
|             if(time <= keys.begin()->first) | ||||
|                 return keys.begin()->second.mValue; | ||||
| 
 | ||||
|             Nif::FloatKeyMap::MapType::const_iterator it = keys.lower_bound(time); | ||||
|             if (it != keys.end()) | ||||
|             { | ||||
|                 float aTime = it->first; | ||||
|                 const Nif::FloatKey* aKey = &it->second; | ||||
| 
 | ||||
|                 assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function
 | ||||
| 
 | ||||
|                 Nif::FloatKeyMap::MapType::const_iterator last = --it; | ||||
|                 float aLastTime = last->first; | ||||
|                 const Nif::FloatKey* aLastKey = &last->second; | ||||
| 
 | ||||
|                 float a = (time - aLastTime) / (aTime - aLastTime); | ||||
|                 return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); | ||||
|             } | ||||
|             else | ||||
|                 return keys.rbegin()->second.mValue; | ||||
|         } | ||||
| 
 | ||||
|         Ogre::Vector3 interpKey(const Nif::Vector3KeyMap::MapType &keys, float time) const | ||||
|         { | ||||
|             if(time <= keys.begin()->first) | ||||
|                 return keys.begin()->second.mValue; | ||||
| 
 | ||||
|             Nif::Vector3KeyMap::MapType::const_iterator it = keys.lower_bound(time); | ||||
|             if (it != keys.end()) | ||||
|             { | ||||
|                 float aTime = it->first; | ||||
|                 const Nif::Vector3Key* aKey = &it->second; | ||||
| 
 | ||||
|                 assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function
 | ||||
| 
 | ||||
|                 Nif::Vector3KeyMap::MapType::const_iterator last = --it; | ||||
|                 float aLastTime = last->first; | ||||
|                 const Nif::Vector3Key* aLastKey = &last->second; | ||||
| 
 | ||||
|                 float a = (time - aLastTime) / (aTime - aLastTime); | ||||
|                 return aLastKey->mValue + ((aKey->mValue - aLastKey->mValue) * a); | ||||
|             } | ||||
|             else | ||||
|                 return keys.rbegin()->second.mValue; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     // FIXME: Should not be here.
 | ||||
|     class DefaultFunction : public Ogre::ControllerFunction<Ogre::Real> | ||||
|     { | ||||
|     private: | ||||
|         float mFrequency; | ||||
|         float mPhase; | ||||
|         float mStartTime; | ||||
|     public: | ||||
|         float mStopTime; | ||||
| 
 | ||||
|     public: | ||||
|         DefaultFunction(const Nif::Controller *ctrl, bool deltaInput) | ||||
|             : Ogre::ControllerFunction<Ogre::Real>(deltaInput) | ||||
|             , mFrequency(ctrl->frequency) | ||||
|             , mPhase(ctrl->phase) | ||||
|             , mStartTime(ctrl->timeStart) | ||||
|             , mStopTime(ctrl->timeStop) | ||||
|         { | ||||
|             if(mDeltaInput) | ||||
|                 mDeltaCount = mPhase; | ||||
|         } | ||||
| 
 | ||||
|         virtual Ogre::Real calculate(Ogre::Real value) | ||||
|         { | ||||
|             if(mDeltaInput) | ||||
|             { | ||||
|                 if (mStopTime - mStartTime == 0.f) | ||||
|                     return 0.f; | ||||
| 
 | ||||
|                 mDeltaCount += value*mFrequency; | ||||
|                 if(mDeltaCount < mStartTime) | ||||
|                     mDeltaCount = mStopTime - std::fmod(mStartTime - mDeltaCount, | ||||
|                                                         mStopTime - mStartTime); | ||||
|                 mDeltaCount = std::fmod(mDeltaCount - mStartTime, | ||||
|                                         mStopTime - mStartTime) + mStartTime; | ||||
|                 return mDeltaCount; | ||||
|             } | ||||
| 
 | ||||
|             value = std::min(mStopTime, std::max(mStartTime, value+mPhase)); | ||||
|             return value; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -1,442 +0,0 @@ | |||
| #include "material.hpp" | ||||
| 
 | ||||
| #include <components/nif/node.hpp> | ||||
| #include <components/misc/resourcehelpers.hpp> | ||||
| #include <components/settings/settings.hpp> | ||||
| #include <components/nifoverrides/nifoverrides.hpp> | ||||
| 
 | ||||
| #include <extern/shiny/Main/Factory.hpp> | ||||
| 
 | ||||
| #include <OgreMaterialManager.h> | ||||
| #include <OgreMaterial.h> | ||||
| 
 | ||||
| #include <boost/functional/hash.hpp> | ||||
| 
 | ||||
| 
 | ||||
| namespace NifOgre | ||||
| { | ||||
| 
 | ||||
| // Conversion of blend / test mode from NIF
 | ||||
| static const char *getBlendFactor(int mode) | ||||
| { | ||||
|     switch(mode) | ||||
|     { | ||||
|     case 0: return "one"; | ||||
|     case 1: return "zero"; | ||||
|     case 2: return "src_colour"; | ||||
|     case 3: return "one_minus_src_colour"; | ||||
|     case 4: return "dest_colour"; | ||||
|     case 5: return "one_minus_dest_colour"; | ||||
|     case 6: return "src_alpha"; | ||||
|     case 7: return "one_minus_src_alpha"; | ||||
|     case 8: return "dest_alpha"; | ||||
|     case 9: return "one_minus_dest_alpha"; | ||||
|     case 10: return "src_alpha_saturate"; | ||||
|     } | ||||
|     std::cerr<< "Unexpected blend mode: "<<mode <<std::endl; | ||||
|     return "src_alpha"; | ||||
| } | ||||
| 
 | ||||
| static const char *getTestMode(int mode) | ||||
| { | ||||
|     switch(mode) | ||||
|     { | ||||
|     case 0: return "always_pass"; | ||||
|     case 1: return "less"; | ||||
|     case 2: return "equal"; | ||||
|     case 3: return "less_equal"; | ||||
|     case 4: return "greater"; | ||||
|     case 5: return "not_equal"; | ||||
|     case 6: return "greater_equal"; | ||||
|     case 7: return "always_fail"; | ||||
|     } | ||||
|     std::cerr<< "Unexpected test mode: "<<mode <<std::endl; | ||||
|     return "less_equal"; | ||||
| } | ||||
| 
 | ||||
| static void setTextureProperties(sh::MaterialInstance* material, const std::string& textureSlotName, const Nif::NiTexturingProperty::Texture& tex) | ||||
| { | ||||
|     material->setProperty(textureSlotName + "UVSet", sh::makeProperty(new sh::IntValue(tex.uvSet))); | ||||
|     const std::string clampMode = textureSlotName + "ClampMode"; | ||||
|     switch (tex.clamp) | ||||
|     { | ||||
|     case 0: | ||||
|         material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("clamp clamp"))); | ||||
|         break; | ||||
|     case 1: | ||||
|         material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("clamp wrap"))); | ||||
|         break; | ||||
|     case 2: | ||||
|         material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("wrap clamp"))); | ||||
|         break; | ||||
|     case 3: | ||||
|     default: | ||||
|         material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("wrap wrap"))); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| Ogre::String NIFMaterialLoader::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, | ||||
|                                             const Nif::NiVertexColorProperty *vertprop, | ||||
|                                             const Nif::NiZBufferProperty *zprop, | ||||
|                                             const Nif::NiSpecularProperty *specprop, | ||||
|                                             const Nif::NiWireframeProperty *wireprop, | ||||
|                                             const Nif::NiStencilProperty *stencilprop, | ||||
|                                             bool &needTangents, bool particleMaterial) | ||||
| { | ||||
|     Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); | ||||
|     Ogre::MaterialPtr material = matMgr.getByName(name); | ||||
|     if(!material.isNull()) | ||||
|         return name; | ||||
| 
 | ||||
|     Ogre::Vector3 ambient(1.0f); | ||||
|     Ogre::Vector3 diffuse(1.0f); | ||||
|     Ogre::Vector3 specular(0.0f); | ||||
|     Ogre::Vector3 emissive(0.0f); | ||||
|     float glossiness = 0.0f; | ||||
|     float alpha = 1.0f; | ||||
|     int alphaFlags = 0; | ||||
|     int alphaTest = 0; | ||||
|     int vertMode = 2; | ||||
|     //int lightMode = 1;
 | ||||
|     int depthFlags = 3; | ||||
|     // Default should be 1, but Bloodmoon's models are broken
 | ||||
|     int specFlags = 0; | ||||
|     int wireFlags = 0; | ||||
|     int drawMode = 1; | ||||
|     Ogre::String texName[7]; | ||||
| 
 | ||||
|     bool vertexColour = (shapedata->colors.size() != 0); | ||||
| 
 | ||||
|     // Texture
 | ||||
|     if(texprop) | ||||
|     { | ||||
|         for(int i = 0;i < 7;i++) | ||||
|         { | ||||
|             if(!texprop->textures[i].inUse) | ||||
|                 continue; | ||||
|             if(texprop->textures[i].texture.empty()) | ||||
|             { | ||||
|                 warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name); | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             const Nif::NiSourceTexture *st = texprop->textures[i].texture.getPtr(); | ||||
|             if(st->external) | ||||
|                 texName[i] = Misc::ResourceHelpers::correctTexturePath(st->filename); | ||||
|             else | ||||
|                 warn("Found internal texture, ignoring."); | ||||
|         } | ||||
| 
 | ||||
|         Nif::ControllerPtr ctrls = texprop->controller; | ||||
|         while(!ctrls.empty()) | ||||
|         { | ||||
|             if (ctrls->recType != Nif::RC_NiFlipController) // Handled in ogrenifloader
 | ||||
|                 warn("Unhandled texture controller "+ctrls->recName+" in "+name); | ||||
|             ctrls = ctrls->next; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Alpha modifiers
 | ||||
|     if(alphaprop) | ||||
|     { | ||||
|         alphaFlags = alphaprop->flags; | ||||
|         alphaTest = alphaprop->data.threshold; | ||||
| 
 | ||||
|         Nif::ControllerPtr ctrls = alphaprop->controller; | ||||
|         while(!ctrls.empty()) | ||||
|         { | ||||
|             warn("Unhandled alpha controller "+ctrls->recName+" in "+name); | ||||
|             ctrls = ctrls->next; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Vertex color handling
 | ||||
|     if(vertprop) | ||||
|     { | ||||
|         vertMode = vertprop->data.vertmode; | ||||
|         // FIXME: Handle lightmode?
 | ||||
|         //lightMode = vertprop->data.lightmode;
 | ||||
| 
 | ||||
|         Nif::ControllerPtr ctrls = vertprop->controller; | ||||
|         while(!ctrls.empty()) | ||||
|         { | ||||
|             warn("Unhandled vertex color controller "+ctrls->recName+" in "+name); | ||||
|             ctrls = ctrls->next; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(zprop) | ||||
|     { | ||||
|         depthFlags = zprop->flags; | ||||
|         // Depth function???
 | ||||
| 
 | ||||
|         Nif::ControllerPtr ctrls = zprop->controller; | ||||
|         while(!ctrls.empty()) | ||||
|         { | ||||
|             warn("Unhandled depth controller "+ctrls->recName+" in "+name); | ||||
|             ctrls = ctrls->next; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(specprop) | ||||
|     { | ||||
|         specFlags = specprop->flags; | ||||
| 
 | ||||
|         Nif::ControllerPtr ctrls = specprop->controller; | ||||
|         while(!ctrls.empty()) | ||||
|         { | ||||
|             warn("Unhandled specular controller "+ctrls->recName+" in "+name); | ||||
|             ctrls = ctrls->next; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(wireprop) | ||||
|     { | ||||
|         wireFlags = wireprop->flags; | ||||
| 
 | ||||
|         Nif::ControllerPtr ctrls = wireprop->controller; | ||||
|         while(!ctrls.empty()) | ||||
|         { | ||||
|             warn("Unhandled wireframe controller "+ctrls->recName+" in "+name); | ||||
|             ctrls = ctrls->next; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(stencilprop) | ||||
|     { | ||||
|         drawMode = stencilprop->data.drawMode; | ||||
|         if (stencilprop->data.enabled) | ||||
|             warn("Unhandled stencil test in "+name); | ||||
| 
 | ||||
|         Nif::ControllerPtr ctrls = stencilprop->controller; | ||||
|         while(!ctrls.empty()) | ||||
|         { | ||||
|             warn("Unhandled stencil controller "+ctrls->recName+" in "+name); | ||||
|             ctrls = ctrls->next; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Material
 | ||||
|     if(matprop) | ||||
|     { | ||||
|         ambient = matprop->data.ambient; | ||||
|         diffuse = matprop->data.diffuse; | ||||
|         specular = matprop->data.specular; | ||||
|         emissive = matprop->data.emissive; | ||||
|         glossiness = matprop->data.glossiness; | ||||
|         alpha = matprop->data.alpha; | ||||
| 
 | ||||
|         Nif::ControllerPtr ctrls = matprop->controller; | ||||
|         while(!ctrls.empty()) | ||||
|         { | ||||
|             if (ctrls->recType != Nif::RC_NiAlphaController && ctrls->recType != Nif::RC_NiMaterialColorController) | ||||
|                 warn("Unhandled material controller "+ctrls->recName+" in "+name); | ||||
|             ctrls = ctrls->next; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (particleMaterial) | ||||
|     { | ||||
|         alpha = 1.f; // Apparently ignored, might be overridden by particle vertex colors?
 | ||||
|     } | ||||
| 
 | ||||
|     { | ||||
|         // Generate a hash out of all properties that can affect the material.
 | ||||
|         size_t h = 0; | ||||
|         boost::hash_combine(h, ambient.x); | ||||
|         boost::hash_combine(h, ambient.y); | ||||
|         boost::hash_combine(h, ambient.z); | ||||
|         boost::hash_combine(h, diffuse.x); | ||||
|         boost::hash_combine(h, diffuse.y); | ||||
|         boost::hash_combine(h, diffuse.z); | ||||
|         boost::hash_combine(h, alpha); | ||||
|         boost::hash_combine(h, specular.x); | ||||
|         boost::hash_combine(h, specular.y); | ||||
|         boost::hash_combine(h, specular.z); | ||||
|         boost::hash_combine(h, glossiness); | ||||
|         boost::hash_combine(h, emissive.x); | ||||
|         boost::hash_combine(h, emissive.y); | ||||
|         boost::hash_combine(h, emissive.z); | ||||
|         for(int i = 0;i < 7;i++) | ||||
|         { | ||||
|             if(!texName[i].empty()) | ||||
|             { | ||||
|                 boost::hash_combine(h, texName[i]); | ||||
|                 boost::hash_combine(h, texprop->textures[i].clamp); | ||||
|                 boost::hash_combine(h, texprop->textures[i].uvSet); | ||||
|             } | ||||
|         } | ||||
|         boost::hash_combine(h, drawMode); | ||||
|         boost::hash_combine(h, vertexColour); | ||||
|         boost::hash_combine(h, alphaFlags); | ||||
|         boost::hash_combine(h, alphaTest); | ||||
|         boost::hash_combine(h, vertMode); | ||||
|         boost::hash_combine(h, depthFlags); | ||||
|         boost::hash_combine(h, specFlags); | ||||
|         boost::hash_combine(h, wireFlags); | ||||
| 
 | ||||
|         std::map<size_t,std::string>::iterator itr = sMaterialMap.find(h); | ||||
|         if (itr != sMaterialMap.end()) | ||||
|         { | ||||
|             // a suitable material exists already - use it
 | ||||
|             sh::MaterialInstance* instance = sh::Factory::getInstance().getMaterialInstance(itr->second); | ||||
|             needTangents = !sh::retrieveValue<sh::StringValue>(instance->getProperty("normalMap"), instance).get().empty(); | ||||
|             return itr->second; | ||||
|         } | ||||
|         // not found, create a new one
 | ||||
|         sMaterialMap.insert(std::make_pair(h, name)); | ||||
|     } | ||||
| 
 | ||||
|     // No existing material like this. Create a new one.
 | ||||
|     sh::MaterialInstance *instance = sh::Factory::getInstance().createMaterialInstance(name, "openmw_objects_base"); | ||||
|     if(vertMode == 0 || !vertexColour) | ||||
|     { | ||||
|         instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); | ||||
|         instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); | ||||
|         instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); | ||||
|         instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("0"))); | ||||
|     } | ||||
|     else if(vertMode == 1) | ||||
|     { | ||||
|         instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); | ||||
|         instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); | ||||
|         instance->setProperty("emissive", sh::makeProperty(new sh::StringValue("vertexcolour"))); | ||||
|         instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("1"))); | ||||
|     } | ||||
|     else if(vertMode == 2) | ||||
|     { | ||||
|         instance->setProperty("ambient", sh::makeProperty(new sh::StringValue("vertexcolour"))); | ||||
|         instance->setProperty("diffuse", sh::makeProperty(new sh::StringValue("vertexcolour"))); | ||||
|         instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); | ||||
|         instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("2"))); | ||||
|     } | ||||
|     else | ||||
|         std::cerr<< "Unhandled vertex mode: "<<vertMode <<std::endl; | ||||
| 
 | ||||
|     if(specFlags) | ||||
|     { | ||||
|         instance->setProperty("specular", sh::makeProperty( | ||||
|             new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); | ||||
|     } | ||||
| 
 | ||||
|     if(wireFlags) | ||||
|     { | ||||
|         instance->setProperty("polygon_mode", sh::makeProperty(new sh::StringValue("wireframe"))); | ||||
|     } | ||||
| 
 | ||||
|     if (drawMode == 1) | ||||
|         instance->setProperty("cullmode", sh::makeProperty(new sh::StringValue("clockwise"))); | ||||
|     else if (drawMode == 2) | ||||
|         instance->setProperty("cullmode", sh::makeProperty(new sh::StringValue("anticlockwise"))); | ||||
|     else if (drawMode == 3) | ||||
|         instance->setProperty("cullmode", sh::makeProperty(new sh::StringValue("none"))); | ||||
| 
 | ||||
|     instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); | ||||
|     instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); | ||||
|     instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture])); | ||||
|     instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); | ||||
|     instance->setProperty("darkMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DarkTexture])); | ||||
|     if (!texName[Nif::NiTexturingProperty::BaseTexture].empty()) | ||||
|     { | ||||
|         instance->setProperty("use_diffuse_map", sh::makeProperty(new sh::BooleanValue(true))); | ||||
|         setTextureProperties(instance, "diffuseMap", texprop->textures[Nif::NiTexturingProperty::BaseTexture]); | ||||
|     } | ||||
|     if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) | ||||
|     { | ||||
|         instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); | ||||
|         setTextureProperties(instance, "emissiveMap", texprop->textures[Nif::NiTexturingProperty::GlowTexture]); | ||||
|     } | ||||
|     if (!texName[Nif::NiTexturingProperty::DetailTexture].empty()) | ||||
|     { | ||||
|         instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); | ||||
|         setTextureProperties(instance, "detailMap", texprop->textures[Nif::NiTexturingProperty::DetailTexture]); | ||||
|     } | ||||
|     if (!texName[Nif::NiTexturingProperty::DarkTexture].empty()) | ||||
|     { | ||||
|         instance->setProperty("use_dark_map", sh::makeProperty(new sh::BooleanValue(true))); | ||||
|         setTextureProperties(instance, "darkMap", texprop->textures[Nif::NiTexturingProperty::DarkTexture]); | ||||
|     } | ||||
| 
 | ||||
|     bool useParallax = !texName[Nif::NiTexturingProperty::BumpTexture].empty() | ||||
|             && texName[Nif::NiTexturingProperty::BumpTexture].find("_nh.") != std::string::npos; | ||||
|     instance->setProperty("use_parallax", sh::makeProperty(new sh::BooleanValue(useParallax))); | ||||
| 
 | ||||
|     for(int i = 0;i < 7;i++) | ||||
|     { | ||||
|         if(i == Nif::NiTexturingProperty::BaseTexture || | ||||
|            i == Nif::NiTexturingProperty::DetailTexture || | ||||
|            i == Nif::NiTexturingProperty::DarkTexture || | ||||
|            i == Nif::NiTexturingProperty::BumpTexture || | ||||
|            i == Nif::NiTexturingProperty::GlowTexture) | ||||
|             continue; | ||||
|         if(!texName[i].empty()) | ||||
|             warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i) + " in " + name); | ||||
|     } | ||||
| 
 | ||||
|     if (vertexColour) | ||||
|         instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); | ||||
| 
 | ||||
|     // Override alpha flags based on our override list (transparency-overrides.cfg)
 | ||||
|     if ((alphaFlags&1) && !texName[0].empty()) | ||||
|     { | ||||
|         NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]); | ||||
|         if (result.first) | ||||
|         { | ||||
|             alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ | ||||
|             alphaTest = result.second; | ||||
|             depthFlags = (1<<0) | (1<<1); // depth_write on, depth_check on
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Add transparency if NiAlphaProperty was present
 | ||||
|     if((alphaFlags&1)) | ||||
|     { | ||||
|         std::string blend_mode; | ||||
|         blend_mode += getBlendFactor((alphaFlags>>1)&0xf); | ||||
|         blend_mode += " "; | ||||
|         blend_mode += getBlendFactor((alphaFlags>>5)&0xf); | ||||
|         instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); | ||||
|     } | ||||
| 
 | ||||
|     if((alphaFlags>>9)&1) | ||||
|     { | ||||
| #ifndef ANDROID | ||||
|         std::string reject; | ||||
|         reject += getTestMode((alphaFlags>>10)&0x7); | ||||
|         reject += " "; | ||||
|         reject += Ogre::StringConverter::toString(alphaTest); | ||||
|         instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); | ||||
| #else | ||||
|         // alpha test not supported in OpenGL ES 2, use manual implementation in shader
 | ||||
|         instance->setProperty("alphaTestMode", sh::makeProperty(new sh::IntValue((alphaFlags>>10)&0x7))); | ||||
|         instance->setProperty("alphaTestValue", sh::makeProperty(new sh::FloatValue(alphaTest/255.f))); | ||||
| #endif | ||||
|     } | ||||
|     else | ||||
|         instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); | ||||
| 
 | ||||
|     // Ogre usually only sorts if depth write is disabled, so we want "force" instead of "on"
 | ||||
|     instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue( | ||||
|         ((alphaFlags&1) && !((alphaFlags>>13)&1)) ? "force" : "off"))); | ||||
| 
 | ||||
|     instance->setProperty("depth_check", sh::makeProperty(new sh::StringValue((depthFlags&1) ? "on" : "off"))); | ||||
|     instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); | ||||
|     // depth_func???
 | ||||
| 
 | ||||
|     if (!texName[0].empty()) | ||||
|         NifOverrides::Overrides::getMaterialOverrides(texName[0], instance); | ||||
| 
 | ||||
|     // Don't use texName, as it may be overridden
 | ||||
|     needTangents = !sh::retrieveValue<sh::StringValue>(instance->getProperty("normalMap"), instance).get().empty(); | ||||
| 
 | ||||
|     return name; | ||||
| } | ||||
| 
 | ||||
| std::map<size_t,std::string> NIFMaterialLoader::sMaterialMap; | ||||
| 
 | ||||
| } | ||||
|  | @ -1,51 +0,0 @@ | |||
| #ifndef COMPONENTS_NIFOGRE_MATERIAL_HPP | ||||
| #define COMPONENTS_NIFOGRE_MATERIAL_HPP | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <string> | ||||
| #include <map> | ||||
| #include <cassert> | ||||
| 
 | ||||
| #include <OgreString.h> | ||||
| 
 | ||||
| namespace Nif | ||||
| { | ||||
|     class ShapeData; | ||||
|     class NiTexturingProperty; | ||||
|     class NiMaterialProperty; | ||||
|     class NiAlphaProperty; | ||||
|     class NiVertexColorProperty; | ||||
|     class NiZBufferProperty; | ||||
|     class NiSpecularProperty; | ||||
|     class NiWireframeProperty; | ||||
|     class NiStencilProperty; | ||||
| } | ||||
| 
 | ||||
| namespace NifOgre | ||||
| { | ||||
| 
 | ||||
| class NIFMaterialLoader { | ||||
|     static void warn(const std::string &msg) | ||||
|     { | ||||
|         std::cerr << "NIFMaterialLoader: Warn: " << msg << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     static std::map<size_t,std::string> sMaterialMap; | ||||
| 
 | ||||
| public: | ||||
|     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, | ||||
|                                     const Nif::NiVertexColorProperty *vertprop, | ||||
|                                     const Nif::NiZBufferProperty *zprop, | ||||
|                                     const Nif::NiSpecularProperty *specprop, | ||||
|                                     const Nif::NiWireframeProperty *wireprop, | ||||
|                                     const Nif::NiStencilProperty *stencilprop, | ||||
|                                     bool &needTangents, bool particleMaterial=false); | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -1,412 +0,0 @@ | |||
| #include "mesh.hpp" | ||||
| 
 | ||||
| #include <limits> | ||||
| 
 | ||||
| #include <OgreMeshManager.h> | ||||
| #include <OgreMesh.h> | ||||
| #include <OgreSubMesh.h> | ||||
| #include <OgreBone.h> | ||||
| #include <OgreHardwareBufferManager.h> | ||||
| #include <OgreMaterialManager.h> | ||||
| #include <OgreSkeletonManager.h> | ||||
| #include <OgreRenderSystem.h> | ||||
| #include <OgreRoot.h> | ||||
| #include <OgreSkeleton.h> | ||||
| #include <OgreKeyFrame.h> | ||||
| 
 | ||||
| #include <components/nif/node.hpp> | ||||
| #include <components/nifcache/nifcache.hpp> | ||||
| #include <components/misc/stringops.hpp> | ||||
| 
 | ||||
| #include "material.hpp" | ||||
| 
 | ||||
| namespace NifOgre | ||||
| { | ||||
| 
 | ||||
| // Helper class that computes the bounding box and of a mesh
 | ||||
| class BoundsFinder | ||||
| { | ||||
|     struct MaxMinFinder | ||||
|     { | ||||
|         float max, min; | ||||
| 
 | ||||
|         MaxMinFinder() | ||||
|         { | ||||
|             min = std::numeric_limits<float>::infinity(); | ||||
|             max = -min; | ||||
|         } | ||||
| 
 | ||||
|         void add(float f) | ||||
|         { | ||||
|             if (f > max) max = f; | ||||
|             if (f < min) min = f; | ||||
|         } | ||||
| 
 | ||||
|         // Return Max(max**2, min**2)
 | ||||
|         float getMaxSquared() | ||||
|         { | ||||
|             float m1 = max*max; | ||||
|             float m2 = min*min; | ||||
|             if (m1 >= m2) return m1; | ||||
|             return m2; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     MaxMinFinder X, Y, Z; | ||||
| 
 | ||||
| public: | ||||
|     // Add 'verts' vertices to the calculation. The 'data' pointer is
 | ||||
|     // expected to point to 3*verts floats representing x,y,z for each
 | ||||
|     // point.
 | ||||
|     void add(float *data, int verts) | ||||
|     { | ||||
|         for (int i=0;i<verts;i++) | ||||
|         { | ||||
|             X.add(*(data++)); | ||||
|             Y.add(*(data++)); | ||||
|             Z.add(*(data++)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // True if this structure has valid values
 | ||||
|     bool isValid() | ||||
|     { | ||||
|         return | ||||
|             minX() <= maxX() && | ||||
|             minY() <= maxY() && | ||||
|             minZ() <= maxZ(); | ||||
|     } | ||||
| 
 | ||||
|     // Compute radius
 | ||||
|     float getRadius() | ||||
|     { | ||||
|         assert(isValid()); | ||||
| 
 | ||||
|         // The radius is computed from the origin, not from the geometric
 | ||||
|         // center of the mesh.
 | ||||
|         return sqrt(X.getMaxSquared() + Y.getMaxSquared() + Z.getMaxSquared()); | ||||
|     } | ||||
| 
 | ||||
|     float minX() { | ||||
|         return X.min; | ||||
|     } | ||||
|     float maxX() { | ||||
|         return X.max; | ||||
|     } | ||||
|     float minY() { | ||||
|         return Y.min; | ||||
|     } | ||||
|     float maxY() { | ||||
|         return Y.max; | ||||
|     } | ||||
|     float minZ() { | ||||
|         return Z.min; | ||||
|     } | ||||
|     float maxZ() { | ||||
|         return Z.max; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; | ||||
| 
 | ||||
| void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape) | ||||
| { | ||||
|     const Nif::NiTriShapeData *data = shape->data.getPtr(); | ||||
|     const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); | ||||
|     std::vector<Ogre::Vector3> srcVerts = data->vertices; | ||||
|     std::vector<Ogre::Vector3> srcNorms = data->normals; | ||||
|     Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; | ||||
|     bool vertShadowBuffer = false; | ||||
| 
 | ||||
|     if(skin != NULL) | ||||
|     { | ||||
|         vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; | ||||
|         vertShadowBuffer = true; | ||||
| 
 | ||||
|         // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be
 | ||||
|         // explicitly attached later.
 | ||||
|         mesh->setSkeletonName(mName); | ||||
| 
 | ||||
|         // Convert vertices and normals to bone space from bind position. It would be
 | ||||
|         // better to transform the bones into bind position, but there doesn't seem to
 | ||||
|         // be a reliable way to do that.
 | ||||
|         std::vector<Ogre::Vector3> newVerts(srcVerts.size(), Ogre::Vector3(0.0f)); | ||||
|         std::vector<Ogre::Vector3> newNorms(srcNorms.size(), Ogre::Vector3(0.0f)); | ||||
| 
 | ||||
|         const Nif::NiSkinData *data = skin->data.getPtr(); | ||||
|         const Nif::NodeList &bones = skin->bones; | ||||
|         for(size_t b = 0;b < bones.length();b++) | ||||
|         { | ||||
|             Ogre::Matrix4 mat; | ||||
|             mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), | ||||
|                               Ogre::Quaternion(data->bones[b].trafo.rotation)); | ||||
|             mat = bones[b]->getWorldTransform() * mat; | ||||
| 
 | ||||
|             const std::vector<Nif::NiSkinData::VertWeight> &weights = data->bones[b].weights; | ||||
|             for(size_t i = 0;i < weights.size();i++) | ||||
|             { | ||||
|                 size_t index = weights[i].vertex; | ||||
|                 float weight = weights[i].weight; | ||||
| 
 | ||||
|                 newVerts.at(index) += (mat*srcVerts[index]) * weight; | ||||
|                 if(newNorms.size() > index) | ||||
|                 { | ||||
|                     Ogre::Vector4 vec4(srcNorms[index][0], srcNorms[index][1], srcNorms[index][2], 0.0f); | ||||
|                     vec4 = mat*vec4 * weight; | ||||
|                     newNorms[index] += Ogre::Vector3(&vec4[0]); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         srcVerts = newVerts; | ||||
|         srcNorms = newNorms; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); | ||||
|         if(skelMgr->getByName(mName).isNull()) | ||||
|         { | ||||
|             // No skinning and no skeleton, so just transform the vertices and
 | ||||
|             // normals into position.
 | ||||
|             Ogre::Matrix4 mat4 = shape->getWorldTransform(); | ||||
|             for(size_t i = 0;i < srcVerts.size();i++) | ||||
|             { | ||||
|                 Ogre::Vector4 vec4(srcVerts[i].x, srcVerts[i].y, srcVerts[i].z, 1.0f); | ||||
|                 vec4 = mat4*vec4; | ||||
|                 srcVerts[i] = Ogre::Vector3(&vec4[0]); | ||||
|             } | ||||
|             for(size_t i = 0;i < srcNorms.size();i++) | ||||
|             { | ||||
|                 Ogre::Vector4 vec4(srcNorms[i].x, srcNorms[i].y, srcNorms[i].z, 0.0f); | ||||
|                 vec4 = mat4*vec4; | ||||
|                 srcNorms[i] = Ogre::Vector3(&vec4[0]); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Set the bounding box first
 | ||||
|     BoundsFinder bounds; | ||||
|     bounds.add(&srcVerts[0][0], srcVerts.size()); | ||||
|     if(!bounds.isValid()) | ||||
|     { | ||||
|         float v[3] = { 0.0f, 0.0f, 0.0f }; | ||||
|         bounds.add(&v[0], 1); | ||||
|     } | ||||
| 
 | ||||
|     mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX()-0.5f, bounds.minY()-0.5f, bounds.minZ()-0.5f, | ||||
|                                           bounds.maxX()+0.5f, bounds.maxY()+0.5f, bounds.maxZ()+0.5f)); | ||||
|     mesh->_setBoundingSphereRadius(bounds.getRadius()); | ||||
| 
 | ||||
|     // This function is just one long stream of Ogre-barf, but it works
 | ||||
|     // great.
 | ||||
|     Ogre::HardwareBufferManager *hwBufMgr = Ogre::HardwareBufferManager::getSingletonPtr(); | ||||
|     Ogre::HardwareVertexBufferSharedPtr vbuf; | ||||
|     Ogre::HardwareIndexBufferSharedPtr ibuf; | ||||
|     Ogre::VertexBufferBinding *bind; | ||||
|     Ogre::VertexDeclaration *decl; | ||||
|     int nextBuf = 0; | ||||
| 
 | ||||
|     Ogre::SubMesh *sub = mesh->createSubMesh(); | ||||
| 
 | ||||
|     // Add vertices
 | ||||
|     sub->useSharedVertices = false; | ||||
|     sub->vertexData = new Ogre::VertexData(); | ||||
|     sub->vertexData->vertexStart = 0; | ||||
|     sub->vertexData->vertexCount = srcVerts.size(); | ||||
| 
 | ||||
|     decl = sub->vertexData->vertexDeclaration; | ||||
|     bind = sub->vertexData->vertexBufferBinding; | ||||
|     if(srcVerts.size()) | ||||
|     { | ||||
|         vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), | ||||
|                                             srcVerts.size(), vertUsage, vertShadowBuffer); | ||||
|         vbuf->writeData(0, vbuf->getSizeInBytes(), &srcVerts[0][0], true); | ||||
| 
 | ||||
|         decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); | ||||
|         bind->setBinding(nextBuf++, vbuf); | ||||
|     } | ||||
| 
 | ||||
|     // Vertex normals
 | ||||
|     if(srcNorms.size()) | ||||
|     { | ||||
|         vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), | ||||
|                                             srcNorms.size(), vertUsage, vertShadowBuffer); | ||||
|         vbuf->writeData(0, vbuf->getSizeInBytes(), &srcNorms[0][0], true); | ||||
| 
 | ||||
|         decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); | ||||
|         bind->setBinding(nextBuf++, vbuf); | ||||
|     } | ||||
| 
 | ||||
|     // Vertex colors
 | ||||
|     const std::vector<Ogre::Vector4> &colors = data->colors; | ||||
|     if(colors.size()) | ||||
|     { | ||||
|         Ogre::RenderSystem *rs = Ogre::Root::getSingleton().getRenderSystem(); | ||||
|         std::vector<Ogre::RGBA> colorsRGB(colors.size()); | ||||
|         for(size_t i = 0;i < colorsRGB.size();i++) | ||||
|         { | ||||
|             Ogre::ColourValue clr(colors[i][0], colors[i][1], colors[i][2], colors[i][3]); | ||||
|             rs->convertColourValue(clr, &colorsRGB[i]); | ||||
|         } | ||||
|         vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), | ||||
|                                             colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC); | ||||
|         vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB[0], true); | ||||
|         decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); | ||||
|         bind->setBinding(nextBuf++, vbuf); | ||||
|     } | ||||
| 
 | ||||
|     // Texture UV coordinates
 | ||||
|     size_t numUVs = data->uvlist.size(); | ||||
|     if (numUVs) | ||||
|     { | ||||
|         size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); | ||||
| 
 | ||||
|         for(size_t i = 0; i < numUVs; i++) | ||||
|             decl->addElement(nextBuf, elemSize*i, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); | ||||
| 
 | ||||
|         vbuf = hwBufMgr->createVertexBuffer(decl->getVertexSize(nextBuf), srcVerts.size(), | ||||
|                                             Ogre::HardwareBuffer::HBU_STATIC); | ||||
| 
 | ||||
|         std::vector<Ogre::Vector2> allUVs; | ||||
|         allUVs.reserve(srcVerts.size()*numUVs); | ||||
|         for (size_t vert = 0; vert<srcVerts.size(); ++vert) | ||||
|             for(size_t i = 0; i < numUVs; i++) | ||||
|                 allUVs.push_back(data->uvlist[i][vert]); | ||||
| 
 | ||||
|         vbuf->writeData(0, elemSize*srcVerts.size()*numUVs, &allUVs[0], true); | ||||
| 
 | ||||
|         bind->setBinding(nextBuf++, vbuf); | ||||
|     } | ||||
| 
 | ||||
|     // Triangle faces
 | ||||
|     const std::vector<short> &srcIdx = data->triangles; | ||||
|     if(srcIdx.size()) | ||||
|     { | ||||
|         ibuf = hwBufMgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, srcIdx.size(), | ||||
|                                            Ogre::HardwareBuffer::HBU_STATIC); | ||||
|         ibuf->writeData(0, ibuf->getSizeInBytes(), &srcIdx[0], true); | ||||
|         sub->indexData->indexBuffer = ibuf; | ||||
|         sub->indexData->indexCount = srcIdx.size(); | ||||
|         sub->indexData->indexStart = 0; | ||||
|     } | ||||
| 
 | ||||
|     // Assign bone weights for this TriShape
 | ||||
|     if(skin != NULL) | ||||
|     { | ||||
|         Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(mName); | ||||
| 
 | ||||
|         const Nif::NiSkinData *data = skin->data.getPtr(); | ||||
|         const Nif::NodeList &bones = skin->bones; | ||||
|         for(size_t i = 0;i < bones.length();i++) | ||||
|         { | ||||
|             Ogre::VertexBoneAssignment boneInf; | ||||
|             boneInf.boneIndex = skel->getBone(bones[i]->name)->getHandle(); | ||||
| 
 | ||||
|             const std::vector<Nif::NiSkinData::VertWeight> &weights = data->bones[i].weights; | ||||
|             for(size_t j = 0;j < weights.size();j++) | ||||
|             { | ||||
|                 boneInf.vertexIndex = weights[j].vertex; | ||||
|                 boneInf.weight = weights[j].weight; | ||||
|                 sub->addBoneAssignment(boneInf); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
|     const Nif::NiWireframeProperty *wireprop = NULL; | ||||
|     const Nif::NiStencilProperty *stencilprop = NULL; | ||||
|     bool needTangents = false; | ||||
| 
 | ||||
|     shape->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, stencilprop); | ||||
|     std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, | ||||
|                                                          texprop, matprop, alphaprop, | ||||
|                                                          vertprop, zprop, specprop, | ||||
|                                                          wireprop, stencilprop, needTangents); | ||||
|     if(matname.length() > 0) | ||||
|         sub->setMaterialName(matname); | ||||
| 
 | ||||
|     // build tangents if the material needs them
 | ||||
|     if (needTangents) | ||||
|     { | ||||
|         unsigned short src,dest; | ||||
|         if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest)) | ||||
|             mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     if(!shape->controller.empty()) | ||||
|     { | ||||
|         Nif::ControllerPtr ctrl = shape->controller; | ||||
|         do { | ||||
|             // Load GeomMorpherController into an Ogre::Pose and Animation
 | ||||
|             if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) | ||||
|             { | ||||
|                 const Nif::NiGeomMorpherController *geom = | ||||
|                         static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr()); | ||||
| 
 | ||||
|                 const std::vector<Nif::NiMorphData::MorphData>& morphs = geom->data.getPtr()->mMorphs; | ||||
|                 // Note we are not interested in morph 0, which just contains the original vertices
 | ||||
|                 for (unsigned int i = 1; i < morphs.size(); ++i) | ||||
|                 { | ||||
|                     Ogre::Pose* pose = mesh->createPose(i); | ||||
|                     const Nif::NiMorphData::MorphData& data = morphs[i]; | ||||
|                     for (unsigned int v = 0; v < data.mVertices.size(); ++v) | ||||
|                         pose->addVertex(v, data.mVertices[v]); | ||||
| 
 | ||||
|                     Ogre::String animationID = Ogre::StringConverter::toString(ctrl->recIndex) | ||||
|                             + "_" + Ogre::StringConverter::toString(i); | ||||
|                     Ogre::VertexAnimationTrack* track = | ||||
|                             mesh->createAnimation(animationID, 0) | ||||
|                             ->createVertexTrack(1, Ogre::VAT_POSE); | ||||
|                     Ogre::VertexPoseKeyFrame* keyframe = track->createVertexPoseKeyFrame(0); | ||||
|                     keyframe->addPoseReference(i-1, 1); | ||||
|                 } | ||||
| 
 | ||||
|                 break; | ||||
|             } | ||||
|         } while(!(ctrl=ctrl->next).empty()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| NIFMeshLoader::NIFMeshLoader(const std::string &name, const std::string &group, size_t idx) | ||||
|   : mName(name), mGroup(group), mShapeIndex(idx) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void NIFMeshLoader::loadResource(Ogre::Resource *resource) | ||||
| { | ||||
|     Ogre::Mesh *mesh = static_cast<Ogre::Mesh*>(resource); | ||||
|     OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!"); | ||||
| 
 | ||||
|     Nif::NIFFilePtr nif = Nif::Cache::getInstance().load(mName); | ||||
|     if(mShapeIndex >= nif->numRecords()) | ||||
|     { | ||||
|         Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); | ||||
|         if(!skelMgr->getByName(mName).isNull()) | ||||
|             mesh->setSkeletonName(mName); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const Nif::Record *record = nif->getRecord(mShapeIndex); | ||||
|     createSubMesh(mesh, static_cast<const Nif::NiTriShape*>(record)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void NIFMeshLoader::createMesh(const std::string &name, const std::string &fullname, const std::string &group, size_t idx) | ||||
| { | ||||
|     NIFMeshLoader::LoaderMap::iterator loader; | ||||
|     loader = sLoaders.insert(std::make_pair(fullname, NIFMeshLoader(name, group, idx))).first; | ||||
| 
 | ||||
|     Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); | ||||
|     Ogre::MeshPtr mesh = meshMgr.createManual(fullname, group, &loader->second); | ||||
|     mesh->setAutoBuildEdgeLists(false); | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  | @ -1,55 +0,0 @@ | |||
| #ifndef COMPONENTS_NIFOGRE_MESH_HPP | ||||
| #define COMPONENTS_NIFOGRE_MESH_HPP | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <string> | ||||
| #include <map> | ||||
| #include <cassert> | ||||
| 
 | ||||
| #include <OgreResource.h> | ||||
| 
 | ||||
| namespace Nif | ||||
| { | ||||
|     class NiTriShape; | ||||
| } | ||||
| 
 | ||||
| namespace NifOgre | ||||
| { | ||||
| 
 | ||||
| /** Manual resource loader for NiTriShapes. This is the main class responsible
 | ||||
|  * for translating the internal NIF meshes into something Ogre can use. | ||||
|  */ | ||||
| class NIFMeshLoader : Ogre::ManualResourceLoader | ||||
| { | ||||
|     static void warn(const std::string &msg) | ||||
|     { | ||||
|         std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     static void fail(const std::string &msg) | ||||
|     { | ||||
|         std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; | ||||
|         abort(); | ||||
|     } | ||||
| 
 | ||||
|     std::string mName; | ||||
|     std::string mGroup; | ||||
|     size_t mShapeIndex; | ||||
| 
 | ||||
|     // Convert NiTriShape to Ogre::SubMesh
 | ||||
|     void createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape); | ||||
| 
 | ||||
|     typedef std::map<std::string,NIFMeshLoader> LoaderMap; | ||||
|     static LoaderMap sLoaders; | ||||
| 
 | ||||
|     NIFMeshLoader(const std::string &name, const std::string &group, size_t idx); | ||||
| 
 | ||||
|     virtual void loadResource(Ogre::Resource *resource); | ||||
| 
 | ||||
| public: | ||||
|     static void createMesh(const std::string &name, const std::string &fullname, const std::string &group, size_t idx); | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,151 +0,0 @@ | |||
| /*
 | ||||
|   OpenMW - The completely unofficial reimplementation of Morrowind | ||||
|   Copyright (C) 2008-2010  Nicolay Korslund | ||||
|   Email: < korslund@gmail.com > | ||||
|   WWW: http://openmw.sourceforge.net/
 | ||||
| 
 | ||||
|   This file (ogre_nif_loader.h) is part of the OpenMW package. | ||||
| 
 | ||||
|   OpenMW is distributed as free software: you can redistribute it | ||||
|   and/or modify it under the terms of the GNU General Public License | ||||
|   version 3, as published by the Free Software Foundation. | ||||
| 
 | ||||
|   This program is distributed in the hope that it will be useful, but | ||||
|   WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|   General Public License for more details. | ||||
| 
 | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   version 3 along with this program. If not, see | ||||
|   http://www.gnu.org/licenses/ .
 | ||||
| 
 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef OPENMW_COMPONENTS_NIFOGRE_OGRENIFLOADER_HPP | ||||
| #define OPENMW_COMPONENTS_NIFOGRE_OGRENIFLOADER_HPP | ||||
| 
 | ||||
| #include <OgreResource.h> | ||||
| #include <OgreMaterial.h> | ||||
| #include <OgreController.h> | ||||
| 
 | ||||
| #include <vector> | ||||
| #include <string> | ||||
| #include <map> | ||||
| 
 | ||||
| 
 | ||||
| // FIXME: This namespace really doesn't do anything Nif-specific. Any supportable
 | ||||
| // model format should go through this.
 | ||||
| namespace NifOgre | ||||
| { | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Clones materials as necessary to not make controllers affect other objects (that share the original material). | ||||
|  */ | ||||
| class MaterialControllerManager | ||||
| { | ||||
| public: | ||||
|     ~MaterialControllerManager(); | ||||
| 
 | ||||
|     /// @attention if \a movable is an Entity, it needs to have *one* SubEntity
 | ||||
|     Ogre::MaterialPtr getWritableMaterial (Ogre::MovableObject* movable); | ||||
| 
 | ||||
| private: | ||||
|     std::map<Ogre::MovableObject*, Ogre::MaterialPtr> mClonedMaterials; | ||||
| }; | ||||
| 
 | ||||
| typedef std::multimap<float,std::string> TextKeyMap; | ||||
| static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; | ||||
| struct ObjectScene { | ||||
|     Ogre::Entity *mSkelBase; | ||||
|     std::vector<Ogre::Entity*> mEntities; | ||||
|     std::vector<Ogre::ParticleSystem*> mParticles; | ||||
|     std::vector<Ogre::Light*> mLights; | ||||
| 
 | ||||
|     // Nodes that should always face the camera when rendering
 | ||||
|     std::vector<Ogre::Node*> mBillboardNodes; | ||||
| 
 | ||||
|     Ogre::SceneManager* mSceneMgr; | ||||
| 
 | ||||
|     // The maximum length on any of the controllers. For animations with controllers, but no text keys, consider this the animation length.
 | ||||
|     float mMaxControllerLength; | ||||
| 
 | ||||
|     TextKeyMap mTextKeys; | ||||
| 
 | ||||
|     MaterialControllerManager mMaterialControllerMgr; | ||||
| 
 | ||||
|     std::vector<Ogre::Controller<Ogre::Real> > mControllers; | ||||
| 
 | ||||
|     ObjectScene(Ogre::SceneManager* sceneMgr) : mSkelBase(0), mMaxControllerLength(0), mSceneMgr(sceneMgr) | ||||
|     { } | ||||
| 
 | ||||
|     ~ObjectScene(); | ||||
| 
 | ||||
|     // Rotate nodes in mBillboardNodes so they face the given camera
 | ||||
|     void rotateBillboardNodes(Ogre::Camera* camera); | ||||
| 
 | ||||
|     void setVisibilityFlags (unsigned int flags); | ||||
| 
 | ||||
|     // This is called internally by the OgreNifLoader once all elements of the
 | ||||
|     // scene have been attached to their respective nodes.
 | ||||
|     void _notifyAttached(); | ||||
| }; | ||||
| 
 | ||||
| typedef Ogre::SharedPtr<ObjectScene> ObjectScenePtr; | ||||
| 
 | ||||
| 
 | ||||
| class Loader | ||||
| { | ||||
| public: | ||||
|     static ObjectScenePtr createObjects(Ogre::Entity *parent, const std::string &bonename, | ||||
|                                         const std::string& filter, | ||||
|                                     Ogre::SceneNode *parentNode, | ||||
|                                     std::string name, | ||||
|                                     const std::string &group="General"); | ||||
| 
 | ||||
|     static ObjectScenePtr createObjects(Ogre::SceneNode *parentNode, | ||||
|                                     std::string name, | ||||
|                                     const std::string &group="General"); | ||||
| 
 | ||||
|     static ObjectScenePtr createObjectBase(Ogre::SceneNode *parentNode, | ||||
|                                        std::string name, | ||||
|                                        const std::string &group="General"); | ||||
| 
 | ||||
|     /// Set whether or not nodes marked as "MRK" should be shown.
 | ||||
|     /// These should be hidden ingame, but visible in the editior.
 | ||||
|     /// Default: false.
 | ||||
|     static void setShowMarkers(bool show); | ||||
| 
 | ||||
|     static void createKfControllers(Ogre::Entity *skelBase, | ||||
|                                     const std::string &name, | ||||
|                                     TextKeyMap &textKeys, | ||||
|                                     std::vector<Ogre::Controller<Ogre::Real> > &ctrls); | ||||
| 
 | ||||
| private: | ||||
|     static bool sShowMarkers; | ||||
| }; | ||||
| 
 | ||||
| // FIXME: Should be with other general Ogre extensions.
 | ||||
| template<typename T> | ||||
| class NodeTargetValue : public Ogre::ControllerValue<T> | ||||
| { | ||||
| protected: | ||||
|     Ogre::Node *mNode; | ||||
| 
 | ||||
| public: | ||||
|     NodeTargetValue(Ogre::Node *target) : mNode(target) | ||||
|     { } | ||||
| 
 | ||||
|     virtual Ogre::Quaternion getRotation(T value) const = 0; | ||||
|     virtual Ogre::Vector3 getTranslation(T value) const = 0; | ||||
|     virtual Ogre::Vector3 getScale(T value) const = 0; | ||||
| 
 | ||||
|     void setNode(Ogre::Node *target) | ||||
|     { mNode = target; } | ||||
|     Ogre::Node *getNode() const | ||||
|     { return mNode; } | ||||
| }; | ||||
| typedef Ogre::SharedPtr<NodeTargetValue<Ogre::Real> > NodeTargetValueRealPtr; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -1,773 +0,0 @@ | |||
| #include "particles.hpp" | ||||
| 
 | ||||
| #include <OgreStringConverter.h> | ||||
| #include <OgreParticleSystem.h> | ||||
| #include <OgreParticleEmitter.h> | ||||
| #include <OgreParticleAffector.h> | ||||
| #include <OgreParticle.h> | ||||
| #include <OgreBone.h> | ||||
| #include <OgreTagPoint.h> | ||||
| #include <OgreEntity.h> | ||||
| #include <OgreSkeletonInstance.h> | ||||
| #include <OgreSceneNode.h> | ||||
| #include <OgreSceneManager.h> | ||||
| 
 | ||||
| /* FIXME: "Nif" isn't really an appropriate emitter name. */ | ||||
| class NifEmitter : public Ogre::ParticleEmitter | ||||
| { | ||||
| public: | ||||
|     std::vector<Ogre::Bone*> mEmitterBones; | ||||
|     Ogre::Bone* mParticleBone; | ||||
| 
 | ||||
|     Ogre::ParticleSystem* getPartSys() { return mParent; } | ||||
| 
 | ||||
|     /** Command object for the emitter width (see Ogre::ParamCommand).*/ | ||||
|     class CmdWidth : public Ogre::ParamCommand | ||||
|     { | ||||
|     public: | ||||
|         Ogre::String doGet(const void *target) const | ||||
|         { | ||||
|             return Ogre::StringConverter::toString(static_cast<const NifEmitter*>(target)->getWidth()); | ||||
|         } | ||||
|         void doSet(void *target, const Ogre::String &val) | ||||
|         { | ||||
|             static_cast<NifEmitter*>(target)->setWidth(Ogre::StringConverter::parseReal(val)); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /** Command object for the emitter height (see Ogre::ParamCommand).*/ | ||||
|     class CmdHeight : public Ogre::ParamCommand | ||||
|     { | ||||
|     public: | ||||
|         Ogre::String doGet(const void *target) const | ||||
|         { | ||||
|             return Ogre::StringConverter::toString(static_cast<const NifEmitter*>(target)->getHeight()); | ||||
|         } | ||||
|         void doSet(void *target, const Ogre::String &val) | ||||
|         { | ||||
|             static_cast<NifEmitter*>(target)->setHeight(Ogre::StringConverter::parseReal(val)); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /** Command object for the emitter depth (see Ogre::ParamCommand).*/ | ||||
|     class CmdDepth : public Ogre::ParamCommand | ||||
|     { | ||||
|     public: | ||||
|         Ogre::String doGet(const void *target) const | ||||
|         { | ||||
|             return Ogre::StringConverter::toString(static_cast<const NifEmitter*>(target)->getDepth()); | ||||
|         } | ||||
|         void doSet(void *target, const Ogre::String &val) | ||||
|         { | ||||
|             static_cast<NifEmitter*>(target)->setDepth(Ogre::StringConverter::parseReal(val)); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /** Command object for the emitter vertical_direction (see Ogre::ParamCommand).*/ | ||||
|     class CmdVerticalDir : public Ogre::ParamCommand | ||||
|     { | ||||
|     public: | ||||
|         Ogre::String doGet(const void *target) const | ||||
|         { | ||||
|             const NifEmitter *self = static_cast<const NifEmitter*>(target); | ||||
|             return Ogre::StringConverter::toString(self->getVerticalDirection().valueDegrees()); | ||||
|         } | ||||
|         void doSet(void *target, const Ogre::String &val) | ||||
|         { | ||||
|             NifEmitter *self = static_cast<NifEmitter*>(target); | ||||
|             self->setVerticalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val))); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /** Command object for the emitter vertical_angle (see Ogre::ParamCommand).*/ | ||||
|     class CmdVerticalAngle : public Ogre::ParamCommand | ||||
|     { | ||||
|     public: | ||||
|         Ogre::String doGet(const void *target) const | ||||
|         { | ||||
|             const NifEmitter *self = static_cast<const NifEmitter*>(target); | ||||
|             return Ogre::StringConverter::toString(self->getVerticalAngle().valueDegrees()); | ||||
|         } | ||||
|         void doSet(void *target, const Ogre::String &val) | ||||
|         { | ||||
|             NifEmitter *self = static_cast<NifEmitter*>(target); | ||||
|             self->setVerticalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val))); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /** Command object for the emitter horizontal_direction (see Ogre::ParamCommand).*/ | ||||
|     class CmdHorizontalDir : public Ogre::ParamCommand | ||||
|     { | ||||
|     public: | ||||
|         Ogre::String doGet(const void *target) const | ||||
|         { | ||||
|             const NifEmitter *self = static_cast<const NifEmitter*>(target); | ||||
|             return Ogre::StringConverter::toString(self->getHorizontalDirection().valueDegrees()); | ||||
|         } | ||||
|         void doSet(void *target, const Ogre::String &val) | ||||
|         { | ||||
|             NifEmitter *self = static_cast<NifEmitter*>(target); | ||||
|             self->setHorizontalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val))); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /** Command object for the emitter horizontal_angle (see Ogre::ParamCommand).*/ | ||||
|     class CmdHorizontalAngle : public Ogre::ParamCommand | ||||
|     { | ||||
|     public: | ||||
|         Ogre::String doGet(const void *target) const | ||||
|         { | ||||
|             const NifEmitter *self = static_cast<const NifEmitter*>(target); | ||||
|             return Ogre::StringConverter::toString(self->getHorizontalAngle().valueDegrees()); | ||||
|         } | ||||
|         void doSet(void *target, const Ogre::String &val) | ||||
|         { | ||||
|             NifEmitter *self = static_cast<NifEmitter*>(target); | ||||
|             self->setHorizontalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val))); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     NifEmitter(Ogre::ParticleSystem *psys) | ||||
|       : Ogre::ParticleEmitter(psys) | ||||
|       , mEmitterBones(Ogre::any_cast<NiNodeHolder>(psys->getUserObjectBindings().getUserAny()).mBones) | ||||
|     { | ||||
|         assert (!mEmitterBones.empty()); | ||||
|         Ogre::TagPoint* tag = static_cast<Ogre::TagPoint*>(mParent->getParentNode()); | ||||
|         mParticleBone = static_cast<Ogre::Bone*>(tag->getParent()); | ||||
|         initDefaults("Nif"); | ||||
|     } | ||||
| 
 | ||||
|     /** See Ogre::ParticleEmitter. */ | ||||
|     unsigned short _getEmissionCount(Ogre::Real timeElapsed) | ||||
|     { | ||||
|         // Use basic constant emission
 | ||||
|         return genConstantEmissionCount(timeElapsed); | ||||
|     } | ||||
| 
 | ||||
|     /** See Ogre::ParticleEmitter. */ | ||||
|     void _initParticle(Ogre::Particle *particle) | ||||
|     { | ||||
|         Ogre::Vector3 xOff, yOff, zOff; | ||||
| 
 | ||||
|         // Call superclass
 | ||||
|         ParticleEmitter::_initParticle(particle); | ||||
| 
 | ||||
|         xOff = Ogre::Math::SymmetricRandom() * mXRange; | ||||
|         yOff = Ogre::Math::SymmetricRandom() * mYRange; | ||||
|         zOff = Ogre::Math::SymmetricRandom() * mZRange; | ||||
| 
 | ||||
| #if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) | ||||
|         Ogre::Vector3& position = particle->mPosition; | ||||
|         Ogre::Vector3& direction = particle->mDirection; | ||||
|         Ogre::ColourValue& colour = particle->mColour; | ||||
|         Ogre::Real& totalTimeToLive = particle->mTotalTimeToLive; | ||||
|         Ogre::Real& timeToLive = particle->mTimeToLive; | ||||
| #else | ||||
|         Ogre::Vector3& position = particle->position; | ||||
|         Ogre::Vector3& direction = particle->direction; | ||||
|         Ogre::ColourValue& colour = particle->colour; | ||||
|         Ogre::Real& totalTimeToLive = particle->totalTimeToLive; | ||||
|         Ogre::Real& timeToLive = particle->timeToLive; | ||||
| #endif | ||||
| 
 | ||||
|         Ogre::Node* emitterBone = mEmitterBones.at((int)(::rand()/(RAND_MAX+1.0)*mEmitterBones.size())); | ||||
| 
 | ||||
|         position = xOff + yOff + zOff + | ||||
|                  mParticleBone->_getDerivedOrientation().Inverse() * (emitterBone->_getDerivedPosition() | ||||
|                 - mParticleBone->_getDerivedPosition()); | ||||
| 
 | ||||
|         // Generate complex data by reference
 | ||||
|         genEmissionColour(colour); | ||||
| 
 | ||||
|         // NOTE: We do not use mDirection/mAngle for the initial direction.
 | ||||
|         Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom(); | ||||
|         Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom(); | ||||
|         direction = (mParticleBone->_getDerivedOrientation().Inverse() | ||||
|                      * emitterBone->_getDerivedOrientation() * | ||||
|                                 Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) * | ||||
|                                Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) * | ||||
|                               Ogre::Vector3::UNIT_Z; | ||||
| 
 | ||||
|         genEmissionVelocity(direction); | ||||
| 
 | ||||
|         // Generate simpler data
 | ||||
|         timeToLive = totalTimeToLive = genEmissionTTL(); | ||||
|     } | ||||
| 
 | ||||
|     /** Overloaded to update the trans. matrix */ | ||||
|     void setDirection(const Ogre::Vector3 &dir) | ||||
|     { | ||||
|         ParticleEmitter::setDirection(dir); | ||||
|         genAreaAxes(); | ||||
|     } | ||||
| 
 | ||||
|     /** Sets the size of the area from which particles are emitted.
 | ||||
|     @param | ||||
|         size Vector describing the size of the area. The area extends | ||||
|         around the center point by half the x, y and z components of | ||||
|         this vector. The box is aligned such that it's local Z axis points | ||||
|         along it's direction (see setDirection) | ||||
|     */ | ||||
|     void setSize(const Ogre::Vector3 &size) | ||||
|     { | ||||
|         mSize = size; | ||||
|         genAreaAxes(); | ||||
|     } | ||||
| 
 | ||||
|     /** Sets the size of the area from which particles are emitted.
 | ||||
|     @param x,y,z | ||||
|         Individual axis lengths describing the size of the area. The area | ||||
|         extends around the center point by half the x, y and z components | ||||
|         of this vector. The box is aligned such that it's local Z axis | ||||
|         points along it's direction (see setDirection) | ||||
|     */ | ||||
|     void setSize(Ogre::Real x, Ogre::Real y, Ogre::Real z) | ||||
|     { | ||||
|         mSize.x = x; | ||||
|         mSize.y = y; | ||||
|         mSize.z = z; | ||||
|         genAreaAxes(); | ||||
|     } | ||||
| 
 | ||||
|     /** Sets the width (local x size) of the emitter. */ | ||||
|     void setWidth(Ogre::Real width) | ||||
|     { | ||||
|         mSize.x = width; | ||||
|         genAreaAxes(); | ||||
|     } | ||||
|     /** Gets the width (local x size) of the emitter. */ | ||||
|     Ogre::Real getWidth(void) const | ||||
|     { return mSize.x; } | ||||
|     /** Sets the height (local y size) of the emitter. */ | ||||
|     void setHeight(Ogre::Real height) | ||||
|     { | ||||
|         mSize.y = height; | ||||
|         genAreaAxes(); | ||||
|     } | ||||
|     /** Gets the height (local y size) of the emitter. */ | ||||
|     Ogre::Real getHeight(void) const | ||||
|     { return mSize.y; } | ||||
|     /** Sets the depth (local y size) of the emitter. */ | ||||
|     void setDepth(Ogre::Real depth) | ||||
|     { | ||||
|         mSize.z = depth; | ||||
|         genAreaAxes(); | ||||
|     } | ||||
|     /** Gets the depth (local y size) of the emitter. */ | ||||
|     Ogre::Real getDepth(void) const | ||||
|     { return mSize.z; } | ||||
| 
 | ||||
|     void setVerticalDirection(Ogre::Radian vdir) | ||||
|     { mVerticalDir = vdir; } | ||||
|     Ogre::Radian getVerticalDirection(void) const | ||||
|     { return mVerticalDir; } | ||||
| 
 | ||||
|     void setVerticalAngle(Ogre::Radian vangle) | ||||
|     { mVerticalAngle = vangle; } | ||||
|     Ogre::Radian getVerticalAngle(void) const | ||||
|     { return mVerticalAngle; } | ||||
| 
 | ||||
|     void setHorizontalDirection(Ogre::Radian hdir) | ||||
|     { mHorizontalDir = hdir; } | ||||
|     Ogre::Radian getHorizontalDirection(void) const | ||||
|     { return mHorizontalDir; } | ||||
| 
 | ||||
|     void setHorizontalAngle(Ogre::Radian hangle) | ||||
|     { mHorizontalAngle = hangle; } | ||||
|     Ogre::Radian getHorizontalAngle(void) const | ||||
|     { return mHorizontalAngle; } | ||||
| 
 | ||||
| 
 | ||||
| protected: | ||||
|     /// Size of the area
 | ||||
|     Ogre::Vector3 mSize; | ||||
| 
 | ||||
|     Ogre::Radian mVerticalDir; | ||||
|     Ogre::Radian mVerticalAngle; | ||||
|     Ogre::Radian mHorizontalDir; | ||||
|     Ogre::Radian mHorizontalAngle; | ||||
| 
 | ||||
|     /// Local axes, not normalised, their magnitude reflects area size
 | ||||
|     Ogre::Vector3 mXRange, mYRange, mZRange; | ||||
| 
 | ||||
|     /// Internal method for generating the area axes
 | ||||
|     void genAreaAxes(void) | ||||
|     { | ||||
|         Ogre::Vector3 mLeft = mUp.crossProduct(mDirection); | ||||
|         mXRange = mLeft * (mSize.x * 0.5f); | ||||
|         mYRange = mUp * (mSize.y * 0.5f); | ||||
|         mZRange = mDirection * (mSize.z * 0.5f); | ||||
|     } | ||||
| 
 | ||||
|     /** Internal for initializing some defaults and parameters
 | ||||
|     @return True if custom parameters need initialising | ||||
|     */ | ||||
|     bool initDefaults(const Ogre::String &t) | ||||
|     { | ||||
|         // Defaults
 | ||||
|         mDirection = Ogre::Vector3::UNIT_Z; | ||||
|         mUp = Ogre::Vector3::UNIT_Y; | ||||
|         setSize(100.0f, 100.0f, 100.0f); | ||||
|         mType = t; | ||||
| 
 | ||||
|         // Set up parameters
 | ||||
|         if(createParamDictionary(mType + "Emitter")) | ||||
|         { | ||||
|             addBaseParameters(); | ||||
|             Ogre::ParamDictionary *dict = getParamDictionary(); | ||||
| 
 | ||||
|             // Custom params
 | ||||
|             dict->addParameter(Ogre::ParameterDef("width", | ||||
|                                                   "Width of the shape in world coordinates.", | ||||
|                                                   Ogre::PT_REAL), | ||||
|                                &msWidthCmd); | ||||
|             dict->addParameter(Ogre::ParameterDef("height", | ||||
|                                                   "Height of the shape in world coordinates.", | ||||
|                                                   Ogre::PT_REAL), | ||||
|                                &msHeightCmd); | ||||
|             dict->addParameter(Ogre::ParameterDef("depth", | ||||
|                                                   "Depth of the shape in world coordinates.", | ||||
|                                                   Ogre::PT_REAL), | ||||
|                                &msDepthCmd); | ||||
| 
 | ||||
|             dict->addParameter(Ogre::ParameterDef("vertical_direction", | ||||
|                                                   "Vertical direction of emitted particles (in degrees).", | ||||
|                                                   Ogre::PT_REAL), | ||||
|                                &msVerticalDirCmd); | ||||
|             dict->addParameter(Ogre::ParameterDef("vertical_angle", | ||||
|                                                   "Vertical direction variance of emitted particles (in degrees).", | ||||
|                                                   Ogre::PT_REAL), | ||||
|                                &msVerticalAngleCmd); | ||||
|             dict->addParameter(Ogre::ParameterDef("horizontal_direction", | ||||
|                                                   "Horizontal direction of emitted particles (in degrees).", | ||||
|                                                   Ogre::PT_REAL), | ||||
|                                &msHorizontalDirCmd); | ||||
|             dict->addParameter(Ogre::ParameterDef("horizontal_angle", | ||||
|                                                   "Horizontal direction variance of emitted particles (in degrees).", | ||||
|                                                   Ogre::PT_REAL), | ||||
|                                &msHorizontalAngleCmd); | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     /// Command objects
 | ||||
|     static CmdWidth msWidthCmd; | ||||
|     static CmdHeight msHeightCmd; | ||||
|     static CmdDepth msDepthCmd; | ||||
|     static CmdVerticalDir msVerticalDirCmd; | ||||
|     static CmdVerticalAngle msVerticalAngleCmd; | ||||
|     static CmdHorizontalDir msHorizontalDirCmd; | ||||
|     static CmdHorizontalAngle msHorizontalAngleCmd; | ||||
| }; | ||||
| NifEmitter::CmdWidth NifEmitter::msWidthCmd; | ||||
| NifEmitter::CmdHeight NifEmitter::msHeightCmd; | ||||
| NifEmitter::CmdDepth NifEmitter::msDepthCmd; | ||||
| NifEmitter::CmdVerticalDir NifEmitter::msVerticalDirCmd; | ||||
| NifEmitter::CmdVerticalAngle NifEmitter::msVerticalAngleCmd; | ||||
| NifEmitter::CmdHorizontalDir NifEmitter::msHorizontalDirCmd; | ||||
| NifEmitter::CmdHorizontalAngle NifEmitter::msHorizontalAngleCmd; | ||||
| 
 | ||||
| Ogre::ParticleEmitter* NifEmitterFactory::createEmitter(Ogre::ParticleSystem *psys) | ||||
| { | ||||
|     Ogre::ParticleEmitter *emitter = OGRE_NEW NifEmitter(psys); | ||||
|     mEmitters.push_back(emitter); | ||||
|     return emitter; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class GrowFadeAffector : public Ogre::ParticleAffector | ||||
| { | ||||
| public: | ||||
|     /** Command object for grow_time (see Ogre::ParamCommand).*/ | ||||
|     class CmdGrowTime : public Ogre::ParamCommand | ||||
|     { | ||||
|     public: | ||||
|         Ogre::String doGet(const void *target) const | ||||
|         { | ||||
|             const GrowFadeAffector *self = static_cast<const GrowFadeAffector*>(target); | ||||
|             return Ogre::StringConverter::toString(self->getGrowTime()); | ||||
|         } | ||||
|         void doSet(void *target, const Ogre::String &val) | ||||
|         { | ||||
|             GrowFadeAffector *self = static_cast<GrowFadeAffector*>(target); | ||||
|             self->setGrowTime(Ogre::StringConverter::parseReal(val)); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /** Command object for fade_time (see Ogre::ParamCommand).*/ | ||||
|     class CmdFadeTime : public Ogre::ParamCommand | ||||
|     { | ||||
|     public: | ||||
|         Ogre::String doGet(const void *target) const | ||||
|         { | ||||
|             const GrowFadeAffector *self = static_cast<const GrowFadeAffector*>(target); | ||||
|             return Ogre::StringConverter::toString(self->getFadeTime()); | ||||
|         } | ||||
|         void doSet(void *target, const Ogre::String &val) | ||||
|         { | ||||
|             GrowFadeAffector *self = static_cast<GrowFadeAffector*>(target); | ||||
|             self->setFadeTime(Ogre::StringConverter::parseReal(val)); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /** Default constructor. */ | ||||
|     GrowFadeAffector(Ogre::ParticleSystem *psys) : ParticleAffector(psys) | ||||
|     { | ||||
|         mGrowTime = 0.0f; | ||||
|         mFadeTime = 0.0f; | ||||
| 
 | ||||
|         mType = "GrowFade"; | ||||
| 
 | ||||
|         // Init parameters
 | ||||
|         if(createParamDictionary("GrowFadeAffector")) | ||||
|         { | ||||
|             Ogre::ParamDictionary *dict = getParamDictionary(); | ||||
| 
 | ||||
|             Ogre::String grow_title("grow_time"); | ||||
|             Ogre::String fade_title("fade_time"); | ||||
|             Ogre::String grow_descr("Time from begin to reach full size."); | ||||
|             Ogre::String fade_descr("Time from end to shrink."); | ||||
| 
 | ||||
|             dict->addParameter(Ogre::ParameterDef(grow_title, grow_descr, Ogre::PT_REAL), &msGrowCmd); | ||||
|             dict->addParameter(Ogre::ParameterDef(fade_title, fade_descr, Ogre::PT_REAL), &msFadeCmd); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** See Ogre::ParticleAffector. */ | ||||
|     void _initParticle(Ogre::Particle *particle) | ||||
|     { | ||||
| #if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) | ||||
|         const Ogre::Real life_time     = particle->mTotalTimeToLive; | ||||
|         Ogre::Real       particle_time = particle->mTimeToLive; | ||||
| #else | ||||
|         const Ogre::Real life_time     = particle->totalTimeToLive; | ||||
|         Ogre::Real       particle_time = particle->timeToLive; | ||||
| #endif | ||||
|         Ogre::Real width = mParent->getDefaultWidth(); | ||||
|         Ogre::Real height = mParent->getDefaultHeight(); | ||||
|         if(life_time-particle_time < mGrowTime) | ||||
|         { | ||||
|             Ogre::Real scale = (life_time-particle_time) / mGrowTime; | ||||
|             assert (scale >= 0); | ||||
|             // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail
 | ||||
|             scale = std::max(scale, 0.00001f); | ||||
|             width *= scale; | ||||
|             height *= scale; | ||||
|         } | ||||
|         if(particle_time < mFadeTime) | ||||
|         { | ||||
|             Ogre::Real scale = particle_time / mFadeTime; | ||||
|             assert (scale >= 0); | ||||
|             // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail
 | ||||
|             scale = std::max(scale, 0.00001f); | ||||
|             width *= scale; | ||||
|             height *= scale; | ||||
|         } | ||||
|         particle->setDimensions(width, height); | ||||
|     } | ||||
| 
 | ||||
|     /** See Ogre::ParticleAffector. */ | ||||
|     void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) | ||||
|     { | ||||
|         Ogre::ParticleIterator pi = psys->_getIterator(); | ||||
|         while (!pi.end()) | ||||
|         { | ||||
|             Ogre::Particle *p = pi.getNext(); | ||||
| #if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) | ||||
|         const Ogre::Real life_time     = p->mTotalTimeToLive; | ||||
|         Ogre::Real       particle_time = p->mTimeToLive; | ||||
| #else | ||||
|         const Ogre::Real life_time     = p->totalTimeToLive; | ||||
|         Ogre::Real       particle_time = p->timeToLive; | ||||
| #endif | ||||
|             Ogre::Real width = mParent->getDefaultWidth(); | ||||
|             Ogre::Real height = mParent->getDefaultHeight(); | ||||
|             if(life_time-particle_time < mGrowTime) | ||||
|             { | ||||
|                 Ogre::Real scale = (life_time-particle_time) / mGrowTime; | ||||
|                 assert (scale >= 0); | ||||
|                 // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail
 | ||||
|                 scale = std::max(scale, 0.00001f); | ||||
|                 width *= scale; | ||||
|                 height *= scale; | ||||
|             } | ||||
|             if(particle_time < mFadeTime) | ||||
|             { | ||||
|                 Ogre::Real scale = particle_time / mFadeTime; | ||||
|                 assert (scale >= 0); | ||||
|                 // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail
 | ||||
|                 scale = std::max(scale, 0.00001f); | ||||
|                 width *= scale; | ||||
|                 height *= scale; | ||||
|             } | ||||
|             p->setDimensions(width, height); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void setGrowTime(Ogre::Real time) | ||||
|     { | ||||
|         mGrowTime = time; | ||||
|     } | ||||
|     Ogre::Real getGrowTime() const | ||||
|     { return mGrowTime; } | ||||
| 
 | ||||
|     void setFadeTime(Ogre::Real time) | ||||
|     { | ||||
|         mFadeTime = time; | ||||
|     } | ||||
|     Ogre::Real getFadeTime() const | ||||
|     { return mFadeTime; } | ||||
| 
 | ||||
|     static CmdGrowTime msGrowCmd; | ||||
|     static CmdFadeTime msFadeCmd; | ||||
| 
 | ||||
| protected: | ||||
|     Ogre::Real mGrowTime; | ||||
|     Ogre::Real mFadeTime; | ||||
| }; | ||||
| GrowFadeAffector::CmdGrowTime GrowFadeAffector::msGrowCmd; | ||||
| GrowFadeAffector::CmdFadeTime GrowFadeAffector::msFadeCmd; | ||||
| 
 | ||||
| Ogre::ParticleAffector *GrowFadeAffectorFactory::createAffector(Ogre::ParticleSystem *psys) | ||||
| { | ||||
|     Ogre::ParticleAffector *p = new GrowFadeAffector(psys); | ||||
|     mAffectors.push_back(p); | ||||
|     return p; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class GravityAffector : public Ogre::ParticleAffector | ||||
| { | ||||
|     enum ForceType { | ||||
|         Type_Wind, | ||||
|         Type_Point | ||||
|     }; | ||||
| 
 | ||||
| public: | ||||
|     Ogre::Bone* mEmitterBone; | ||||
|     Ogre::Bone* mParticleBone; | ||||
| 
 | ||||
|     Ogre::ParticleSystem* getPartSys() { return mParent; } | ||||
| 
 | ||||
|     /** Command object for force (see Ogre::ParamCommand).*/ | ||||
|     class CmdForce : public Ogre::ParamCommand | ||||
|     { | ||||
|     public: | ||||
|         Ogre::String doGet(const void *target) const | ||||
|         { | ||||
|             const GravityAffector *self = static_cast<const GravityAffector*>(target); | ||||
|             return Ogre::StringConverter::toString(self->getForce()); | ||||
|         } | ||||
|         void doSet(void *target, const Ogre::String &val) | ||||
|         { | ||||
|             GravityAffector *self = static_cast<GravityAffector*>(target); | ||||
|             self->setForce(Ogre::StringConverter::parseReal(val)); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /** Command object for force_type (see Ogre::ParamCommand).*/ | ||||
|     class CmdForceType : public Ogre::ParamCommand | ||||
|     { | ||||
|         static ForceType getTypeFromString(const Ogre::String &type) | ||||
|         { | ||||
|             if(type == "wind") | ||||
|                 return Type_Wind; | ||||
|             if(type == "point") | ||||
|                 return Type_Point; | ||||
|             OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type string: "+type, | ||||
|                         "CmdForceType::getTypeFromString"); | ||||
|         } | ||||
| 
 | ||||
|         static Ogre::String getStringFromType(ForceType type) | ||||
|         { | ||||
|             switch(type) | ||||
|             { | ||||
|                 case Type_Wind: return "wind"; | ||||
|                 case Type_Point: return "point"; | ||||
|             } | ||||
|             OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type enum: "+Ogre::StringConverter::toString(type), | ||||
|                         "CmdForceType::getStringFromType"); | ||||
|         } | ||||
| 
 | ||||
|     public: | ||||
|         Ogre::String doGet(const void *target) const | ||||
|         { | ||||
|             const GravityAffector *self = static_cast<const GravityAffector*>(target); | ||||
|             return getStringFromType(self->getForceType()); | ||||
|         } | ||||
|         void doSet(void *target, const Ogre::String &val) | ||||
|         { | ||||
|             GravityAffector *self = static_cast<GravityAffector*>(target); | ||||
|             self->setForceType(getTypeFromString(val)); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /** Command object for direction (see Ogre::ParamCommand).*/ | ||||
|     class CmdDirection : public Ogre::ParamCommand | ||||
|     { | ||||
|     public: | ||||
|         Ogre::String doGet(const void *target) const | ||||
|         { | ||||
|             const GravityAffector *self = static_cast<const GravityAffector*>(target); | ||||
|             return Ogre::StringConverter::toString(self->getDirection()); | ||||
|         } | ||||
|         void doSet(void *target, const Ogre::String &val) | ||||
|         { | ||||
|             GravityAffector *self = static_cast<GravityAffector*>(target); | ||||
|             self->setDirection(Ogre::StringConverter::parseVector3(val)); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /** Command object for position (see Ogre::ParamCommand).*/ | ||||
|     class CmdPosition : public Ogre::ParamCommand | ||||
|     { | ||||
|     public: | ||||
|         Ogre::String doGet(const void *target) const | ||||
|         { | ||||
|             const GravityAffector *self = static_cast<const GravityAffector*>(target); | ||||
|             return Ogre::StringConverter::toString(self->getPosition()); | ||||
|         } | ||||
|         void doSet(void *target, const Ogre::String &val) | ||||
|         { | ||||
|             GravityAffector *self = static_cast<GravityAffector*>(target); | ||||
|             self->setPosition(Ogre::StringConverter::parseVector3(val)); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     /** Default constructor. */ | ||||
|     GravityAffector(Ogre::ParticleSystem *psys) | ||||
|       : ParticleAffector(psys) | ||||
|       , mForce(0.0f) | ||||
|       , mForceType(Type_Wind) | ||||
|       , mPosition(0.0f) | ||||
|       , mDirection(0.0f) | ||||
|     { | ||||
|         std::vector<Ogre::Bone*> bones = Ogre::any_cast<NiNodeHolder>(psys->getUserObjectBindings().getUserAny()).mBones; | ||||
|         assert (!bones.empty()); | ||||
|         mEmitterBone = bones[0]; | ||||
|         Ogre::TagPoint* tag = static_cast<Ogre::TagPoint*>(mParent->getParentNode()); | ||||
|         mParticleBone = static_cast<Ogre::Bone*>(tag->getParent()); | ||||
| 
 | ||||
|         mType = "Gravity"; | ||||
| 
 | ||||
|         // Init parameters
 | ||||
|         if(createParamDictionary("GravityAffector")) | ||||
|         { | ||||
|             Ogre::ParamDictionary *dict = getParamDictionary(); | ||||
| 
 | ||||
|             Ogre::String force_title("force"); | ||||
|             Ogre::String force_descr("Amount of force applied to particles."); | ||||
|             Ogre::String force_type_title("force_type"); | ||||
|             Ogre::String force_type_descr("Type of force applied to particles (point or wind)."); | ||||
|             Ogre::String direction_title("direction"); | ||||
|             Ogre::String direction_descr("Direction of wind forces."); | ||||
|             Ogre::String position_title("position"); | ||||
|             Ogre::String position_descr("Position of point forces."); | ||||
| 
 | ||||
|             dict->addParameter(Ogre::ParameterDef(force_title, force_descr, Ogre::PT_REAL), &msForceCmd); | ||||
|             dict->addParameter(Ogre::ParameterDef(force_type_title, force_type_descr, Ogre::PT_STRING), &msForceTypeCmd); | ||||
|             dict->addParameter(Ogre::ParameterDef(direction_title, direction_descr, Ogre::PT_VECTOR3), &msDirectionCmd); | ||||
|             dict->addParameter(Ogre::ParameterDef(position_title, position_descr, Ogre::PT_VECTOR3), &msPositionCmd); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** See Ogre::ParticleAffector. */ | ||||
|     void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) | ||||
|     { | ||||
|         switch(mForceType) | ||||
|         { | ||||
|             case Type_Wind: | ||||
|                 applyWindForce(psys, timeElapsed); | ||||
|                 break; | ||||
|             case Type_Point: | ||||
|                 applyPointForce(psys, timeElapsed); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void setForce(Ogre::Real force) | ||||
|     { mForce = force; } | ||||
|     Ogre::Real getForce() const | ||||
|     { return mForce; } | ||||
| 
 | ||||
|     void setForceType(ForceType type) | ||||
|     { mForceType = type; } | ||||
|     ForceType getForceType() const | ||||
|     { return mForceType; } | ||||
| 
 | ||||
|     void setDirection(const Ogre::Vector3 &dir) | ||||
|     { mDirection = dir; } | ||||
|     const Ogre::Vector3 &getDirection() const | ||||
|     { return mDirection; } | ||||
| 
 | ||||
|     void setPosition(const Ogre::Vector3 &pos) | ||||
|     { mPosition = pos; } | ||||
|     const Ogre::Vector3 &getPosition() const | ||||
|     { return mPosition; } | ||||
| 
 | ||||
|     static CmdForce msForceCmd; | ||||
|     static CmdForceType msForceTypeCmd; | ||||
|     static CmdDirection msDirectionCmd; | ||||
|     static CmdPosition msPositionCmd; | ||||
| 
 | ||||
| protected: | ||||
|     void applyWindForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) | ||||
|     { | ||||
|         const Ogre::Vector3 vec = mDirection * mForce * timeElapsed; | ||||
|         Ogre::ParticleIterator pi = psys->_getIterator(); | ||||
|         while (!pi.end()) | ||||
|         { | ||||
|             Ogre::Particle *p = pi.getNext(); | ||||
| #if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) | ||||
|             p->mDirection += vec; | ||||
| #else | ||||
|             p->direction += vec; | ||||
| #endif | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void applyPointForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) | ||||
|     { | ||||
|         const Ogre::Real force = mForce * timeElapsed; | ||||
|         Ogre::ParticleIterator pi = psys->_getIterator(); | ||||
|         while (!pi.end()) | ||||
|         { | ||||
|             Ogre::Particle *p = pi.getNext(); | ||||
| #if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) | ||||
|             Ogre::Vector3 position = p->mPosition; | ||||
| #else | ||||
|             Ogre::Vector3 position = p->position; | ||||
| #endif | ||||
| 
 | ||||
|             Ogre::Vector3 vec = (mPosition - position).normalisedCopy() * force; | ||||
| #if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) | ||||
|             p->mDirection += vec; | ||||
| #else | ||||
|             p->direction += vec; | ||||
| #endif | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     float mForce; | ||||
| 
 | ||||
|     ForceType mForceType; | ||||
| 
 | ||||
|     Ogre::Vector3 mPosition; | ||||
|     Ogre::Vector3 mDirection; | ||||
| }; | ||||
| GravityAffector::CmdForce GravityAffector::msForceCmd; | ||||
| GravityAffector::CmdForceType GravityAffector::msForceTypeCmd; | ||||
| GravityAffector::CmdDirection GravityAffector::msDirectionCmd; | ||||
| GravityAffector::CmdPosition GravityAffector::msPositionCmd; | ||||
| 
 | ||||
| Ogre::ParticleAffector *GravityAffectorFactory::createAffector(Ogre::ParticleSystem *psys) | ||||
| { | ||||
|     Ogre::ParticleAffector *p = new GravityAffector(psys); | ||||
|     mAffectors.push_back(p); | ||||
|     return p; | ||||
| } | ||||
|  | @ -1,50 +0,0 @@ | |||
| #ifndef OENGINE_OGRE_PARTICLES_H | ||||
| #define OENGINE_OGRE_PARTICLES_H | ||||
| 
 | ||||
| #include <OgreParticleEmitterFactory.h> | ||||
| #include <OgreParticleAffectorFactory.h> | ||||
| 
 | ||||
| /** Factory class for NifEmitter. */ | ||||
| class NifEmitterFactory : public Ogre::ParticleEmitterFactory | ||||
| { | ||||
| public: | ||||
|     /** See ParticleEmitterFactory */ | ||||
|     Ogre::String getName() const | ||||
|     { return "Nif"; } | ||||
| 
 | ||||
|     /** See ParticleEmitterFactory */ | ||||
|     Ogre::ParticleEmitter* createEmitter(Ogre::ParticleSystem *psys); | ||||
| }; | ||||
| 
 | ||||
| /** Factory class for GrowFadeAffector. */ | ||||
| class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory | ||||
| { | ||||
|     /** See Ogre::ParticleAffectorFactory */ | ||||
|     Ogre::String getName() const | ||||
|     { return "GrowFade"; } | ||||
| 
 | ||||
|     /** See Ogre::ParticleAffectorFactory */ | ||||
|     Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); | ||||
| }; | ||||
| 
 | ||||
| /** Factory class for GravityAffector. */ | ||||
| class GravityAffectorFactory : public Ogre::ParticleAffectorFactory | ||||
| { | ||||
|     /** See Ogre::ParticleAffectorFactory */ | ||||
|     Ogre::String getName() const | ||||
|     { return "Gravity"; } | ||||
| 
 | ||||
|     /** See Ogre::ParticleAffectorFactory */ | ||||
|     Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); | ||||
| }; | ||||
| 
 | ||||
| struct NiNodeHolder | ||||
| { | ||||
|     std::vector<Ogre::Bone*> mBones; | ||||
| 
 | ||||
|     // Ogre::Any needs this for some reason
 | ||||
|     friend std::ostream& operator<<(std::ostream& o, const NiNodeHolder& r) | ||||
|     { return o; } | ||||
| }; | ||||
| 
 | ||||
| #endif /* OENGINE_OGRE_PARTICLES_H */ | ||||
|  | @ -1,179 +0,0 @@ | |||
| #include "skeleton.hpp" | ||||
| 
 | ||||
| #include <OgreSkeletonManager.h> | ||||
| #include <OgreResource.h> | ||||
| #include <OgreSkeleton.h> | ||||
| #include <OgreBone.h> | ||||
| 
 | ||||
| #include <components/nif/node.hpp> | ||||
| #include <components/nifcache/nifcache.hpp> | ||||
| #include <components/misc/stringops.hpp> | ||||
| 
 | ||||
| namespace NifOgre | ||||
| { | ||||
| 
 | ||||
| void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent) | ||||
| { | ||||
|     Ogre::Bone *bone; | ||||
|     if (node->name.empty()) | ||||
|     { | ||||
|         // HACK: use " " instead of empty name, otherwise Ogre will replace it with an auto-generated
 | ||||
|         // name in SkeletonInstance::cloneBoneAndChildren.
 | ||||
|         static const char* emptyname = " "; | ||||
|         if (!skel->hasBone(emptyname)) | ||||
|             bone = skel->createBone(emptyname); | ||||
|         else | ||||
|             bone = skel->createBone(); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         if(!skel->hasBone(node->name)) | ||||
|             bone = skel->createBone(node->name); | ||||
|         else | ||||
|             bone = skel->createBone(); | ||||
|     } | ||||
| 
 | ||||
|     if(parent) parent->addChild(bone); | ||||
|     mNifToOgreHandleMap[node->recIndex] = bone->getHandle(); | ||||
| 
 | ||||
|     bone->setOrientation(node->trafo.rotation); | ||||
|     bone->setPosition(node->trafo.pos); | ||||
|     bone->setScale(Ogre::Vector3(node->trafo.scale)); | ||||
|     bone->setBindingPose(); | ||||
| 
 | ||||
|     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_NiBSAnimationNode || /* Handled in the object loader */ | ||||
|          node->recType == Nif::RC_NiBillboardNode || /* Handled in the object loader */ | ||||
|          node->recType == Nif::RC_NiBSParticleNode || | ||||
|          node->recType == Nif::RC_NiCamera || | ||||
|          node->recType == Nif::RC_NiAutoNormalParticles || | ||||
|          node->recType == Nif::RC_NiRotatingParticles | ||||
|          )) | ||||
|         warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); | ||||
| 
 | ||||
|     Nif::ControllerPtr ctrl = node->controller; | ||||
|     while(!ctrl.empty()) | ||||
|     { | ||||
|         if(!(ctrl->recType == Nif::RC_NiParticleSystemController || | ||||
|              ctrl->recType == Nif::RC_NiBSPArrayController || | ||||
|              ctrl->recType == Nif::RC_NiVisController || | ||||
|              ctrl->recType == Nif::RC_NiUVController || | ||||
|              ctrl->recType == Nif::RC_NiKeyframeController || | ||||
|              ctrl->recType == Nif::RC_NiGeomMorpherController | ||||
|              )) | ||||
|             warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); | ||||
|         ctrl = ctrl->next; | ||||
|     } | ||||
| 
 | ||||
|     const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(node); | ||||
|     if(ninode) | ||||
|     { | ||||
|         const Nif::NodeList &children = ninode->children; | ||||
|         for(size_t i = 0;i < children.length();i++) | ||||
|         { | ||||
|             if(!children[i].empty()) | ||||
|                 buildBones(skel, children[i].getPtr(), bone); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) | ||||
| { | ||||
|     Ogre::Skeleton *skel = dynamic_cast<Ogre::Skeleton*>(resource); | ||||
|     OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); | ||||
| 
 | ||||
|     Nif::NIFFilePtr nif(Nif::Cache::getInstance().load(skel->getName())); | ||||
|     const Nif::Node *node = static_cast<const Nif::Node*>(nif->getRoot(0)); | ||||
| 
 | ||||
|     try { | ||||
|         buildBones(skel, node); | ||||
|     } | ||||
|     catch(std::exception &e) { | ||||
|         std::cerr<< "Exception while loading "<<skel->getName() <<std::endl; | ||||
|         std::cerr<< e.what() <<std::endl; | ||||
|         return; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool NIFSkeletonLoader::needSkeleton(const Nif::Node *node) | ||||
| { | ||||
|     /* We need to be a little aggressive here, since some NIFs have a crap-ton
 | ||||
|      * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: | ||||
|      * There are no bones used for skinning, there are no keyframe controllers, there | ||||
|      * are no nodes named "AttachLight" or "ArrowBone", and the tree consists of NiNode, | ||||
|      * NiTriShape, and RootCollisionNode types only. | ||||
|      */ | ||||
|     if(node->boneTrafo) | ||||
|         return true; | ||||
| 
 | ||||
|     if(!node->controller.empty()) | ||||
|     { | ||||
|         Nif::ControllerPtr ctrl = node->controller; | ||||
|         do { | ||||
|             if(ctrl->recType == Nif::RC_NiKeyframeController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) | ||||
|                 return true; | ||||
|         } while(!(ctrl=ctrl->next).empty()); | ||||
|     } | ||||
| 
 | ||||
|     if (node->name == "AttachLight" || node->name == "ArrowBone") | ||||
|         return true; | ||||
| 
 | ||||
|     if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) | ||||
|     { | ||||
|         const Nif::NiNode *ninode = static_cast<const Nif::NiNode*>(node); | ||||
|         const Nif::NodeList &children = ninode->children; | ||||
|         for(size_t i = 0;i < children.length();i++) | ||||
|         { | ||||
|             if(!children[i].empty()) | ||||
|             { | ||||
|                 if(needSkeleton(children[i].getPtr())) | ||||
|                     return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|     if(node->recType == Nif::RC_NiTriShape) | ||||
|         return false; | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| Ogre::SkeletonPtr NIFSkeletonLoader::createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) | ||||
| { | ||||
|     bool forceskel = false; | ||||
|     std::string::size_type extpos = name.rfind('.'); | ||||
|     if(extpos != std::string::npos && name.compare(extpos, name.size()-extpos, ".nif") == 0) | ||||
|     { | ||||
|         Ogre::ResourceGroupManager &resMgr = Ogre::ResourceGroupManager::getSingleton(); | ||||
|         forceskel = resMgr.resourceExistsInAnyGroup(name.substr(0, extpos)+".kf"); | ||||
|     } | ||||
| 
 | ||||
|     if(forceskel || needSkeleton(node)) | ||||
|     { | ||||
|         Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); | ||||
|         return skelMgr.create(name, group, true, &sLoaders[name]); | ||||
|     } | ||||
| 
 | ||||
|     return Ogre::SkeletonPtr(); | ||||
| } | ||||
| 
 | ||||
| // Looks up an Ogre Bone handle ID from a NIF's record index. Should only be
 | ||||
| // used when the bone name is insufficient as this is a relatively slow lookup
 | ||||
| int NIFSkeletonLoader::lookupOgreBoneHandle(const std::string &nifname, int idx) | ||||
| { | ||||
|     LoaderMap::const_iterator loader = sLoaders.find(nifname); | ||||
|     if(loader != sLoaders.end()) | ||||
|     { | ||||
|         std::map<int,int>::const_iterator entry = loader->second.mNifToOgreHandleMap.find(idx); | ||||
|         if(entry != loader->second.mNifToOgreHandleMap.end()) | ||||
|             return entry->second; | ||||
|     } | ||||
|     throw std::runtime_error("Invalid NIF record lookup ("+nifname+", index "+Ogre::StringConverter::toString(idx)+")"); | ||||
| } | ||||
| 
 | ||||
| NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; | ||||
| 
 | ||||
| } | ||||
|  | @ -1,62 +0,0 @@ | |||
| #ifndef COMPONENTS_NIFOGRE_SKELETON_HPP | ||||
| #define COMPONENTS_NIFOGRE_SKELETON_HPP | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <string> | ||||
| #include <cassert> | ||||
| 
 | ||||
| #include <OgreResource.h> | ||||
| 
 | ||||
| #include "ogrenifloader.hpp" | ||||
| 
 | ||||
| namespace Nif | ||||
| { | ||||
|     class NiTextKeyExtraData; | ||||
|     class Node; | ||||
|     class NiKeyframeController; | ||||
| } | ||||
| 
 | ||||
| namespace NifOgre | ||||
| { | ||||
| 
 | ||||
| /** Manual resource loader for NIF skeletons. This is the main class
 | ||||
|     responsible for translating the internal NIF skeleton structure into | ||||
|     something Ogre can use (includes animations and node TextKeyData). | ||||
|  */ | ||||
| class NIFSkeletonLoader : public Ogre::ManualResourceLoader | ||||
| { | ||||
|     static void warn(const std::string &msg) | ||||
|     { | ||||
|         std::cerr << "NIFSkeletonLoader: Warn: " << msg << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     static void fail(const std::string &msg) | ||||
|     { | ||||
|         std::cerr << "NIFSkeletonLoader: Fail: "<< msg << std::endl; | ||||
|         abort(); | ||||
|     } | ||||
| 
 | ||||
|     void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent=NULL); | ||||
| 
 | ||||
|     static bool needSkeleton(const Nif::Node *node); | ||||
| 
 | ||||
|     // Lookup to retrieve an Ogre bone handle for a given Nif record index
 | ||||
|     std::map<int,int> mNifToOgreHandleMap; | ||||
| 
 | ||||
|     typedef std::map<std::string,NIFSkeletonLoader> LoaderMap; | ||||
|     static LoaderMap sLoaders; | ||||
| 
 | ||||
| public: | ||||
|     void loadResource(Ogre::Resource *resource); | ||||
| 
 | ||||
|     static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node); | ||||
| 
 | ||||
|     // Looks up an Ogre Bone handle ID from a NIF's record index. Should only
 | ||||
|     // be used when the bone name is insufficient as this is a relatively slow
 | ||||
|     // lookup
 | ||||
|     static int lookupOgreBoneHandle(const std::string &nifname, int idx); | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -15,8 +15,6 @@ | |||
| #include <OSX/macUtils.h> | ||||
| #endif | ||||
| 
 | ||||
| #include <components/nifogre/particles.hpp> | ||||
| 
 | ||||
| #include <boost/filesystem/path.hpp> | ||||
| #include <boost/filesystem/fstream.hpp> | ||||
| 
 | ||||
|  | @ -118,8 +116,6 @@ namespace OgreInit | |||
|         loadPlugins(); | ||||
|         #endif | ||||
| 
 | ||||
|         loadParticleFactories(); | ||||
| 
 | ||||
|         return mRoot; | ||||
|     } | ||||
| 
 | ||||
|  | @ -128,16 +124,6 @@ namespace OgreInit | |||
|         delete mRoot; | ||||
|         delete Ogre::LogManager::getSingletonPtr(); | ||||
| 
 | ||||
|         std::vector<Ogre::ParticleEmitterFactory*>::iterator ei; | ||||
|         for(ei = mEmitterFactories.begin();ei != mEmitterFactories.end();++ei) | ||||
|             OGRE_DELETE (*ei); | ||||
|         mEmitterFactories.clear(); | ||||
| 
 | ||||
|         std::vector<Ogre::ParticleAffectorFactory*>::iterator ai; | ||||
|         for(ai = mAffectorFactories.begin();ai != mAffectorFactories.end();++ai) | ||||
|             OGRE_DELETE (*ai); | ||||
|         mAffectorFactories.clear(); | ||||
| 
 | ||||
|         #ifdef ENABLE_PLUGIN_GL | ||||
|         delete mGLPlugin; | ||||
|         mGLPlugin = NULL; | ||||
|  | @ -221,22 +207,4 @@ namespace OgreInit | |||
|         if (!Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot)) | ||||
|             throw std::runtime_error("Required Plugin_ParticleFX for Ogre not found!"); | ||||
|     } | ||||
| 
 | ||||
|     void OgreInit::loadParticleFactories() | ||||
|     { | ||||
|         Ogre::ParticleEmitterFactory *emitter; | ||||
|         emitter = OGRE_NEW NifEmitterFactory(); | ||||
|         Ogre::ParticleSystemManager::getSingleton().addEmitterFactory(emitter); | ||||
|         mEmitterFactories.push_back(emitter); | ||||
| 
 | ||||
|         Ogre::ParticleAffectorFactory *affector; | ||||
|         affector = OGRE_NEW GrowFadeAffectorFactory(); | ||||
|         Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); | ||||
|         mAffectorFactories.push_back(affector); | ||||
| 
 | ||||
|         affector = OGRE_NEW GravityAffectorFactory(); | ||||
|         Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); | ||||
|         mAffectorFactories.push_back(affector); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -48,13 +48,10 @@ namespace OgreInit | |||
|         ~OgreInit(); | ||||
| 
 | ||||
|     private: | ||||
|         std::vector<Ogre::ParticleEmitterFactory*> mEmitterFactories; | ||||
|         std::vector<Ogre::ParticleAffectorFactory*> mAffectorFactories; | ||||
|         Ogre::Root* mRoot; | ||||
| 
 | ||||
|         void loadStaticPlugins(); | ||||
|         void loadPlugins(); | ||||
|         void loadParticleFactories(); | ||||
| 
 | ||||
|         #ifdef ENABLE_PLUGIN_CgProgramManager | ||||
|         Ogre::CgPlugin* mCgPlugin; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue