Guest User

Untitled

a guest
Jun 20th, 2012
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 39.67 KB | None | 0 0
  1. #include <Ogre.h>
  2. #include <OgreMesh.h>
  3. #include <OgreAny.h>
  4. #include <OgreException.h>
  5.  
  6. #include "nif_loader.h"
  7.  
  8. #include <niflib.h>
  9. #include <obj/NiAVObject.h>
  10. #include <obj/NiObject.h>
  11. #include <obj/NiNode.h>
  12. #include <obj/NiTriShape.h>
  13. #include <obj/NiTriShapeData.h>
  14. #include <obj/NiStringExtraData.h>
  15. #include <obj/NiTextKeyExtraData.h>
  16. #include <obj/NiVertexColorProperty.h>
  17. #include <obj/NiTexturingProperty.h>
  18. #include <obj/NiMaterialProperty.h>
  19. #include <obj/NiZBufferProperty.h>
  20. #include <obj/NiAlphaProperty.h>
  21. #include <obj/NiSourceTexture.h>
  22. #include <obj/NiSkinInstance.h>
  23. #include <obj/NiSkinData.h>
  24. #include <obj/NiDynamicEffect.h>
  25. #include <obj/RootCollisionNode.h>
  26. #include <obj/NiSequenceStreamHelper.h>
  27. #include <obj/NiTimeController.h>
  28. #include <obj/NiKeyframeController.h>
  29. #include <obj/NiKeyframeData.h>
  30.  
  31. /* An std::istream that reads from an Ogre::DataStream, for niflib */
  32. class InStream : public std::istream {
  33.     class DataStreamBuf : public std::streambuf {
  34.         Ogre::DataStreamPtr istream;
  35.  
  36.         char buffer[4096];
  37.  
  38.         virtual int_type underflow()
  39.         {
  40.             if(gptr() == egptr())
  41.             {
  42.                 std::streamsize todo = sizeof(buffer);
  43.  
  44.                 if((todo=istream->read(buffer, todo)) > 0)
  45.                     setg(buffer, buffer, buffer+todo);
  46.             }
  47.             if(gptr() == egptr())
  48.                 return traits_type::eof();
  49.             return (*gptr())&0xFF;
  50.         }
  51.  
  52.         virtual pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode)
  53.         {
  54.             if((mode&std::ios_base::out))
  55.                 return traits_type::eof();
  56.  
  57.             pos_type pos = -1;
  58.             switch(whence)
  59.             {
  60.             case std::ios_base::beg:
  61.                 istream->seek(offset);
  62.                 pos = istream->tell();
  63.                 break;
  64.  
  65.             case std::ios_base::cur:
  66.                 offset -= off_type(egptr()-gptr());
  67.                 istream->skip(offset);
  68.                 pos = istream->tell();
  69.                 break;
  70.  
  71.             case std::ios_base::end:
  72.                 if(offset <= 0)
  73.                 {
  74.                     istream->seek(istream->size()+offset);
  75.                     pos = istream->tell();
  76.                 }
  77.                 break;
  78.  
  79.             default:
  80.                 pos = traits_type::eof();
  81.             }
  82.             if(pos >= 0)
  83.                 setg(0, 0, 0);
  84.             return pos;
  85.         }
  86.         virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
  87.         {
  88.             if(pos != pos_type(off_type(pos)))
  89.                 return traits_type::eof();
  90.             return seekoff(off_type(pos), std::ios_base::beg, mode);
  91.         }
  92.  
  93.     public:
  94.         DataStreamBuf(Ogre::DataStreamPtr stream)
  95.           : istream(stream)
  96.         { }
  97.         virtual ~DataStreamBuf()
  98.         { }
  99.     };
  100.  
  101. public:
  102.     InStream(Ogre::DataStreamPtr stream)
  103.       : std::istream(new DataStreamBuf(stream))
  104.     { }
  105.     virtual ~InStream()
  106.     { delete rdbuf(); }
  107. };
  108.  
  109.  
  110. /* Easy niflib to Ogre type converters */
  111. static inline Ogre::Quaternion ConvertQuaternion(const Niflib::Quaternion &rhs)
  112. {
  113.     return Ogre::Quaternion(rhs.w, rhs.x, rhs.y, rhs.z);
  114. }
  115.  
  116. static inline Ogre::Vector3 ConvertVector3(const Niflib::Vector3 &rhs)
  117. {
  118.     return Ogre::Vector3(rhs.x, rhs.y, rhs.z);
  119. }
  120.  
  121.  
  122. using namespace Niflib;
  123.  
  124. static Ogre::SceneBlendFactor getBlendFactor(NiAlphaProperty::BlendFunc func)
  125. {
  126.     switch(func)
  127.     {
  128.     case NiAlphaProperty::BF_ONE:
  129.         return Ogre::SBF_ONE;
  130.     case NiAlphaProperty::BF_ZERO:
  131.         return Ogre::SBF_ZERO;
  132.     case NiAlphaProperty::BF_SRC_COLOR:
  133.         return Ogre::SBF_SOURCE_COLOUR;
  134.     case NiAlphaProperty::BF_ONE_MINUS_SRC_COLOR:
  135.         return Ogre::SBF_ONE_MINUS_SOURCE_COLOUR;
  136.     case NiAlphaProperty::BF_DST_COLOR:
  137.         return Ogre::SBF_DEST_COLOUR;
  138.     case NiAlphaProperty::BF_ONE_MINUS_DST_COLOR:
  139.         return Ogre::SBF_ONE_MINUS_DEST_COLOUR;
  140.     case NiAlphaProperty::BF_SRC_ALPHA:
  141.         return Ogre::SBF_SOURCE_ALPHA;
  142.     case NiAlphaProperty::BF_ONE_MINUS_SRC_ALPHA:
  143.         return Ogre::SBF_ONE_MINUS_SOURCE_ALPHA;
  144.     case NiAlphaProperty::BF_DST_ALPHA:
  145.         return Ogre::SBF_DEST_ALPHA;
  146.     case NiAlphaProperty::BF_ONE_MINUS_DST_ALPHA:
  147.         return Ogre::SBF_ONE_MINUS_DEST_ALPHA;
  148.     case NiAlphaProperty::BF_SRC_ALPHA_SATURATE:
  149.         // Can't handle this mode? :/
  150.         //return Ogre::SBF_SOURCE_ALPHA_SATURATE;*/
  151.         break;
  152.     }
  153.     Ogre::LogManager::getSingleton().stream() << "Unhandled blend function "<<func;
  154.     return Ogre::SBF_SOURCE_ALPHA;
  155. }
  156.  
  157. static Ogre::CompareFunction getTestMode(NiAlphaProperty::TestFunc func)
  158. {
  159.     switch(func)
  160.     {
  161.     case NiAlphaProperty::TF_ALWAYS:
  162.         return Ogre::CMPF_ALWAYS_PASS;
  163.     case NiAlphaProperty::TF_LESS:
  164.         return Ogre::CMPF_LESS;
  165.     case NiAlphaProperty::TF_EQUAL:
  166.         return Ogre::CMPF_EQUAL;
  167.     case NiAlphaProperty::TF_LEQUAL:
  168.         return Ogre::CMPF_LESS_EQUAL;
  169.     case NiAlphaProperty::TF_GREATER:
  170.         return Ogre::CMPF_GREATER;
  171.     case NiAlphaProperty::TF_NOTEQUAL:
  172.         return Ogre::CMPF_NOT_EQUAL;
  173.     case NiAlphaProperty::TF_GEQUAL:
  174.         return Ogre::CMPF_GREATER_EQUAL;
  175.     case NiAlphaProperty::TF_NEVER:
  176.         return Ogre::CMPF_ALWAYS_FAIL;
  177.     }
  178.     Ogre::LogManager::getSingleton().stream() << "Unhandled compare function "<<func;
  179.     return Ogre::CMPF_ALWAYS_PASS;
  180. }
  181.  
  182. static Ogre::CompareFunction getTestMode(ZCompareMode func)
  183. {
  184.     switch(func)
  185.     {
  186.     case ZCOMP_ALWAYS:
  187.         return Ogre::CMPF_ALWAYS_PASS;
  188.     case ZCOMP_LESS:
  189.         return Ogre::CMPF_LESS;
  190.     case ZCOMP_EQUAL:
  191.         return Ogre::CMPF_EQUAL;
  192.     case ZCOMP_LESS_EQUAL:
  193.         return Ogre::CMPF_LESS_EQUAL;
  194.     case ZCOMP_GREATER:
  195.         return Ogre::CMPF_GREATER;
  196.     case ZCOMP_NOT_EQUAL:
  197.         return Ogre::CMPF_NOT_EQUAL;
  198.     case ZCOMP_GREATER_EQUAL:
  199.         return Ogre::CMPF_GREATER_EQUAL;
  200.     case ZCOMP_NEVER:
  201.         return Ogre::CMPF_ALWAYS_FAIL;
  202.     }
  203.     Ogre::LogManager::getSingleton().stream() << "Unhandled compare function "<<func;
  204.     return Ogre::CMPF_ALWAYS_PASS;
  205. }
  206.  
  207. static Ogre::LayerBlendOperation getLayerBlend(ApplyMode mode)
  208. {
  209.     switch(mode)
  210.     {
  211.     case APPLY_REPLACE:
  212.         return Ogre::LBO_REPLACE;
  213.     case APPLY_DECAL:
  214.         return Ogre::LBO_ALPHA_BLEND;
  215.     case APPLY_MODULATE:
  216.         return Ogre::LBO_MODULATE;
  217.     case APPLY_HILIGHT:
  218.     case APPLY_HILIGHT2:
  219.         /* How to? */
  220.         break;
  221.     }
  222.     Ogre::LogManager::getSingleton().stream() << "Unhandled layer blend "<<mode;
  223.     return Ogre::LBO_REPLACE;
  224. }
  225.  
  226. static Ogre::TrackVertexColourType getVertColorTracking(VertMode mode)
  227. {
  228.     switch(mode)
  229.     {
  230.     case VERT_MODE_SRC_IGNORE:
  231.         return Ogre::TVC_NONE;
  232.     case VERT_MODE_SRC_EMISSIVE:
  233.         return Ogre::TVC_EMISSIVE;
  234.     case VERT_MODE_SRC_AMB_DIF:
  235.         return Ogre::TVC_AMBIENT | Ogre::TVC_DIFFUSE;
  236.     }
  237.     Ogre::LogManager::getSingleton().stream() << "Unhandled vertex color tacking " << mode;
  238.     return Ogre::TVC_NONE;
  239. }
  240.  
  241.  
  242. static void createMaterial(const Ogre::String &name, const Ogre::String &groupName,
  243.                            NiTriShapeRef shape)
  244. {
  245.     Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create(name, "General");
  246.     Ogre::Pass *pass = material->getTechnique(0)->getPass(0);
  247.  
  248.     // This assigns the textures to this material. If the texture name is
  249.     // a file name, and this file exists (in a resource directory), it
  250.     // will automatically be loaded when needed. If not (such as for
  251.     // internal NIF textures that we might support later), we should
  252.     // insert a manual loader for the texture.
  253.     NiTexturingPropertyRef textures = DynamicCast<NiTexturingProperty>(shape->GetPropertyByType(NiTexturingProperty::TYPE));
  254.     if(textures)
  255.     {
  256.         for(int i = 0;i < textures->GetTextureCount();i++)
  257.         {
  258.             if(!textures->HasTexture(i))
  259.                 continue;
  260.             TexDesc desc = textures->GetTexture(i);
  261.  
  262.             NiSourceTextureRef st = desc.source;
  263.             if(!st->IsTextureExternal())
  264.             {
  265.                 Ogre::LogManager::getSingleton().logMessage("Found internal texture, ignoring.");
  266.                 continue;
  267.             }
  268.  
  269.             /* This checks if the file actually exists. If it doesn't, it will
  270.              * try replacing the extension with .dds instead and search for
  271.              * that. Bethesda at some at some point converted all their BSA
  272.              * textures from tga to dds for increased load speed, but all
  273.              * texture file name references were kept as .tga.
  274.              */
  275.             Ogre::String tname = "textures/" + st->GetTextureFileName();
  276.             if(!Ogre::ResourceGroupManager::getSingleton().resourceExists(groupName, tname))
  277.             {
  278.                 // Change texture extension to .dds
  279.                 tname.replace(tname.rfind('.'), tname.length(), ".dds");
  280.             }
  281.  
  282.             Ogre::TextureUnitState *txt = pass->createTextureUnitState(tname);
  283.             if(i == 0) // diffuse texture
  284.                 txt->setColourOperation(getLayerBlend(textures->GetApplyMode()));
  285.             else if(i == 1) // dark texture
  286.                 txt->setColourOperation(Ogre::LBO_MODULATE);
  287.             else // skip remaining
  288.             {
  289.                 txt->setColourOperationEx(Ogre::LBX_SOURCE1, Ogre::LBS_CURRENT);
  290.                 txt->setAlphaOperation(Ogre::LBX_SOURCE1, Ogre::LBS_CURRENT);
  291.             }
  292.  
  293.             txt->setTextureCoordSet(desc.uvSet);
  294.             if(desc.clampMode == CLAMP_S_CLAMP_T)
  295.                 txt->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP, Ogre::TextureUnitState::TAM_CLAMP,
  296.                                               Ogre::TextureUnitState::TAM_CLAMP);
  297.             else if(desc.clampMode == WRAP_S_CLAMP_T)
  298.                 txt->setTextureAddressingMode(Ogre::TextureUnitState::TAM_WRAP, Ogre::TextureUnitState::TAM_CLAMP,
  299.                                               Ogre::TextureUnitState::TAM_CLAMP);
  300.             else if(desc.clampMode == CLAMP_S_WRAP_T)
  301.                 txt->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP, Ogre::TextureUnitState::TAM_WRAP,
  302.                                               Ogre::TextureUnitState::TAM_CLAMP);
  303.             else if(desc.clampMode == WRAP_S_WRAP_T)
  304.                 txt->setTextureAddressingMode(Ogre::TextureUnitState::TAM_WRAP, Ogre::TextureUnitState::TAM_WRAP,
  305.                                               Ogre::TextureUnitState::TAM_CLAMP);
  306.         }
  307.     }
  308.  
  309.     // Add vertex color tracking if NiVertexColorProperty is present
  310.     NiVertexColorPropertyRef vtxc = DynamicCast<NiVertexColorProperty>(shape->GetPropertyByType(NiVertexColorProperty::TYPE));
  311.     if(vtxc)
  312.     {
  313.         pass->setVertexColourTracking(getVertColorTracking(vtxc->GetVertexMode()));
  314.         // FIXME: Handle vtxc->GetLightingMode()?
  315.     }
  316.     else
  317.     {
  318.         pass->setVertexColourTracking(Ogre::TVC_DIFFUSE);
  319.     }
  320.  
  321.     // Add transparency if NiAlphaProperty is set to anything meaningful
  322.     NiAlphaPropertyRef alpha = DynamicCast<NiAlphaProperty>(shape->GetPropertyByType(NiAlphaProperty::TYPE));
  323.     if(alpha)
  324.     {
  325.         if(alpha->GetBlendState())
  326.             pass->setSceneBlending(getBlendFactor(alpha->GetSourceBlendFunc()),
  327.                                    getBlendFactor(alpha->GetDestBlendFunc()));
  328.  
  329.         if(alpha->GetTestState())
  330.             pass->setAlphaRejectSettings(getTestMode(alpha->GetTestFunc()),
  331.                                          alpha->GetTestThreshold());
  332.  
  333.         pass->setTransparentSortingEnabled(alpha->GetTriangleSortMode());
  334.     }
  335.  
  336.     // Set z-buffer options
  337.     NiZBufferPropertyRef zbuf = DynamicCast<NiZBufferProperty>(shape->GetPropertyByType(NiZBufferProperty::TYPE));
  338.     if(zbuf)
  339.     {
  340.         pass->setDepthCheckEnabled(zbuf->GetFlags()&0x1);
  341.         pass->setDepthWriteEnabled((zbuf->GetFlags()>>1)&0x1);
  342.         pass->setDepthFunction(getTestMode(zbuf->GetDepthFunction()));
  343.     }
  344.  
  345.     // Add material bells and whistles
  346.     NiMaterialPropertyRef mat = DynamicCast<NiMaterialProperty>(shape->GetPropertyByType(NiMaterialProperty::TYPE));
  347.     if(mat)
  348.     {
  349.         material->setAmbient(mat->GetAmbientColor().r, mat->GetAmbientColor().g, mat->GetAmbientColor().b);
  350.         material->setDiffuse(mat->GetDiffuseColor().r, mat->GetDiffuseColor().g, mat->GetDiffuseColor().b,
  351.                              mat->GetTransparency());
  352.         material->setSpecular(mat->GetSpecularColor().r, mat->GetSpecularColor().g, mat->GetSpecularColor().b,
  353.                               mat->GetTransparency());
  354.         material->setSelfIllumination(mat->GetEmissiveColor().r, mat->GetEmissiveColor().g, mat->GetEmissiveColor().b);
  355.         material->setShininess(mat->GetGlossiness());
  356.     }
  357. }
  358.  
  359.  
  360. // Convert NiTriShape to Ogre::SubMesh
  361. static void handleNiTriShape(Ogre::Mesh *mesh, NiTriShapeRef shape, int /*flags*/)
  362. {
  363.     // Interpret flags
  364.     //bool hidden    = (flags&0x01) != 0; // Not displayed
  365.     //bool collide   = (flags&0x02) != 0; // Use mesh for collision
  366.     //bool bbcollide = (flags&0x04) != 0; // Use bounding box for collision
  367.  
  368.     // This mesh apparently isn't being used for anything, so don't
  369.     // bother setting it up.
  370.     //if(!collide && !bbcollide && hidden)
  371.     //    return;
  372.  
  373.     // Skip the entire material/submesh phase for hidden nodes
  374.     //if(hidden)
  375.     //    return;
  376.  
  377.     NiTriShapeDataRef data = DynamicCast<NiTriShapeData>(shape->GetData());
  378.     NiSkinInstanceRef skin = shape->GetSkinInstance();
  379.     std::vector<Vector3> srcVerts = data->GetVertices();
  380.     std::vector<Vector3> srcNorms = data->GetNormals();
  381.     if(skin != NULL)
  382.     {
  383.         // Convert vertices and normals back to bone space
  384.         std::vector<Vector3> newVerts(srcVerts.size(), Vector3(0,0,0));
  385.         std::vector<Vector3> newNorms(srcNorms.size(), Vector3(0,0,0));
  386.  
  387.         NiSkinDataRef data = skin->GetSkinData();
  388.         const std::vector<NiNodeRef> &bones = skin->GetBones();
  389.         for(size_t b = 0;b < bones.size();b++)
  390.         {
  391.             Matrix44 mat = data->GetBoneTransform(b) * bones[b]->GetWorldTransform();
  392.  
  393.             const std::vector<SkinWeight> &weights = data->GetBoneWeights(b);
  394.             for(size_t i = 0;i < weights.size();i++)
  395.             {
  396.                 size_t index = weights[i].index;
  397.                 float weight = weights[i].weight;
  398.  
  399.                 newVerts.at(index) += (mat*srcVerts[index]) * weight;
  400.                 if(newNorms.size() > index)
  401.                 {
  402.                     for(size_t j = 0;j < 3;j++)
  403.                     {
  404.                        newNorms[index][j] += mat[j][0]*srcNorms[index][0] * weight;
  405.                        newNorms[index][j] += mat[j][1]*srcNorms[index][1] * weight;
  406.                        newNorms[index][j] += mat[j][2]*srcNorms[index][2] * weight;
  407.                     }
  408.                 }
  409.             }
  410.         }
  411.  
  412.         srcVerts = newVerts;
  413.         srcNorms = newNorms;
  414.     }
  415.     else
  416.     {
  417.         /*// Since Ogre doesn't have any offsets for submeshes (like Nifs do for
  418.         // trishape nodes), we need to manually apply them to the vertices.
  419.         Matrix44 fullTrans = shape->GetWorldTransform() *
  420.                              parent->GetWorldTransform().Inverse();
  421.         for(size_t i = 0;i < srcVerts.size();i++)
  422.             srcVerts[i] = fullTrans * srcVerts[i];
  423.         for(size_t i = 0;i < srcNorms.size();i++)
  424.         {
  425.             float norm[3] = { srcNorms[i].x, srcNorms[i].y, srcNorms[i].z };
  426.             for(size_t j = 0;j < 3;j++)
  427.             {
  428.                srcNorms[i][j]  = fullTrans[j][0] * norm[0];
  429.                srcNorms[i][j] += fullTrans[j][1] * norm[1];
  430.                srcNorms[i][j] += fullTrans[j][2] * norm[2];
  431.             }
  432.         }*/
  433.     }
  434.  
  435.     Ogre::HardwareBufferManager *hwBufMgr = Ogre::HardwareBufferManager::getSingletonPtr();
  436.     Ogre::HardwareVertexBufferSharedPtr vbuf;
  437.     Ogre::HardwareIndexBufferSharedPtr ibuf;
  438.     Ogre::VertexBufferBinding *bind;
  439.     Ogre::VertexDeclaration *decl;
  440.     int nextBuf = 0;
  441.  
  442.     // This function is just one long stream of Ogre-barf, but it works
  443.     // great.
  444.     Ogre::SubMesh *sub = mesh->createSubMesh(shape->GetName());
  445.  
  446.     // Add vertices
  447.     size_t numVerts = data->GetVertexCount();
  448.     sub->useSharedVertices = false;
  449.  
  450.     sub->vertexData = new Ogre::VertexData();
  451.     sub->vertexData->vertexStart = 0;
  452.     sub->vertexData->vertexCount = numVerts;
  453.  
  454.     decl = sub->vertexData->vertexDeclaration;
  455.     bind = sub->vertexData->vertexBufferBinding;
  456.     if(numVerts)
  457.     {
  458.         std::vector<float> verts(numVerts*3);
  459.         for(size_t i = 0;i < numVerts;i++)
  460.         {
  461.             verts[i*3 + 0] = srcVerts[i].x;
  462.             verts[i*3 + 1] = srcVerts[i].y;
  463.             verts[i*3 + 2] = srcVerts[i].z;
  464.         }
  465.  
  466.         vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3),
  467.                                             numVerts, Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, true);
  468.         vbuf->writeData(0, vbuf->getSizeInBytes(), verts.data(), true);
  469.  
  470.         decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
  471.         bind->setBinding(nextBuf++, vbuf);
  472.     }
  473.  
  474.     // Vertex normals
  475.     if(data->GetHasNormals())
  476.     {
  477.         OgreAssert((numVerts==srcNorms.size()), "Normal count does not match vertex count");
  478.         std::vector<float> norms(numVerts*3);
  479.         for(size_t i = 0;i < numVerts;i++)
  480.         {
  481.             norms[i*3 + 0] = srcNorms[i].x;
  482.             norms[i*3 + 1] = srcNorms[i].y;
  483.             norms[i*3 + 2] = srcNorms[i].z;
  484.         }
  485.  
  486.         vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3),
  487.                                             numVerts, Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, true);
  488.         vbuf->writeData(0, vbuf->getSizeInBytes(), norms.data(), true);
  489.  
  490.         decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
  491.         bind->setBinding(nextBuf++, vbuf);
  492.     }
  493.  
  494.     // Vertex colors
  495.     std::vector<Color4> colors = data->GetColors();
  496.     if(colors.size())
  497.     {
  498.         OgreAssert((numVerts==colors.size()), "Color count does not match vertex count");
  499.         Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem();
  500.         std::vector<Ogre::RGBA> colorsRGB(numVerts);
  501.         for(size_t i = 0;i < numVerts;i++)
  502.         {
  503.             Ogre::ColourValue clr(colors[i].r, colors[i].g, colors[i].b, colors[i].a);
  504.             rs->convertColourValue(clr, &colorsRGB[i]);
  505.         }
  506.         vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR),
  507.                                             numVerts, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, true);
  508.         vbuf->writeData(0, vbuf->getSizeInBytes(), colorsRGB.data(), true);
  509.         decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);
  510.         bind->setBinding(nextBuf++, vbuf);
  511.     }
  512.     colors.clear();
  513.  
  514.     // Texture UV coordinates
  515.     size_t numUVs = data->GetUVSetCount();
  516.     if(numUVs)
  517.     {
  518.         size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
  519.         vbuf = hwBufMgr->createVertexBuffer(elemSize, numVerts*numUVs,
  520.                                             Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, true);
  521.         for(size_t i = 0;i < numUVs;i++)
  522.         {
  523.             std::vector<float> uvs(numVerts*2);
  524.             const std::vector<TexCoord> &uvlist = data->GetUVSet(i);
  525.             OgreAssert((numVerts==uvlist.size()), "UV list count does not match vertex count");
  526.             for(size_t j = 0;j < numVerts;j++)
  527.             {
  528.                 uvs[j*2 + 0] = uvlist[j].u;
  529.                 uvs[j*2 + 1] = uvlist[j].v;
  530.             }
  531.             vbuf->writeData(i*numVerts*elemSize, elemSize*numVerts, uvs.data(), true);
  532.             decl->addElement(nextBuf, i*numVerts*elemSize, Ogre::VET_FLOAT2,
  533.                              Ogre::VES_TEXTURE_COORDINATES, i);
  534.         }
  535.         bind->setBinding(nextBuf++, vbuf);
  536.     }
  537.  
  538.     // Triangle faces
  539.     std::vector<Triangle> srcIdx = data->GetTriangles();
  540.     if(srcIdx.size())
  541.     {
  542.         size_t numIdx = srcIdx.size()*3;
  543.         std::vector<uint16_t> idxs(numIdx);
  544.         for(uint32_t i = 0;i < srcIdx.size();i++)
  545.         {
  546.             idxs[i*3 + 0] = srcIdx[i].v1;
  547.             idxs[i*3 + 1] = srcIdx[i].v2;
  548.             idxs[i*3 + 2] = srcIdx[i].v3;
  549.         }
  550.         ibuf = hwBufMgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, numIdx,
  551.                                            Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
  552.         ibuf->writeData(0, ibuf->getSizeInBytes(), idxs.data(), true);
  553.         sub->indexData->indexBuffer = ibuf;
  554.         sub->indexData->indexCount = numIdx;
  555.         sub->indexData->indexStart = 0;
  556.     }
  557.     srcIdx.clear();
  558.  
  559.     // Assign bone weights for this TriShape
  560.     if(skin != NULL)
  561.     {
  562.         // Get the skeleton resource, so weights can be applied
  563.         Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr();
  564.         Ogre::SkeletonPtr skel = skelMgr->getByName(mesh->getSkeletonName());
  565.  
  566.         NiSkinDataRef data = skin->GetSkinData();
  567.         const std::vector<NiNodeRef> &bones = skin->GetBones();
  568.         for(size_t i = 0;i < bones.size();i++)
  569.         {
  570.             Ogre::VertexBoneAssignment boneInf;
  571.             boneInf.boneIndex = skel->getBone(bones[i]->GetName())->getHandle();
  572.  
  573.             const std::vector<SkinWeight> &weights = data->GetBoneWeights(i);
  574.             for(size_t j = 0;j < weights.size();j++)
  575.             {
  576.                 boneInf.vertexIndex = weights[j].index;
  577.                 boneInf.weight = weights[j].weight;
  578.                 sub->addBoneAssignment(boneInf);
  579.             }
  580.         }
  581.     }
  582.  
  583.     // Use the name of the mesh for the material. The mesh name is already
  584.     // unique enough since there's only one NiTriShape/SubMesh, thus only one
  585.     // material.
  586.     const Ogre::String &material = mesh->getName();
  587.     createMaterial(material, mesh->getGroup(), shape);
  588.     sub->setMaterialName(material);
  589. }
  590.  
  591. static bool findNiTriShape(Ogre::Mesh *mesh, const Ogre::String &target, NiAVObjectRef obj, int flags=0)
  592. {
  593.     flags |= obj->GetFlags();
  594.  
  595.     // For trishapes, build the appropriate submesh, material, and junk
  596.     if(obj->IsSameType(NiTriShape::TYPE) && target == obj->GetName())
  597.     {
  598.         handleNiTriShape(mesh, StaticCast<NiTriShape>(obj), flags);
  599.         return true;
  600.     }
  601.  
  602.     if(obj->IsDerivedType(NiNode::TYPE))
  603.     {
  604.         // For NiNodes, loop through children
  605.         NiNodeRef node = StaticCast<NiNode>(obj);
  606.         std::vector<NiAVObjectRef> list = node->GetChildren();
  607.         for(size_t i = 0;i < list.size();i++)
  608.         {
  609.             if(findNiTriShape(mesh, target, list[i], flags))
  610.                 return true;
  611.         }
  612.     }
  613.     return false;
  614. }
  615.  
  616.  
  617. static void buildBones(Ogre::Skeleton *skel, NiNodeRef node, Ogre::Bone *bone = NULL)
  618. {
  619.     //if(bone || node->IsSkeletonRoot())
  620.     {
  621.         Ogre::Bone *newbone = skel->createBone(node->GetName());
  622.         if(!node->IsSkeletonRoot() && bone)
  623.             bone->addChild(newbone);
  624.  
  625.         Vector3 srcTrans = node->GetLocalTranslation();
  626.         Matrix33 srcRot = node->GetLocalRotation();
  627.         float scale = node->GetLocalScale();
  628.  
  629.         Ogre::Vector3 trans(srcTrans.x, srcTrans.y, srcTrans.z);
  630.         Ogre::Matrix3 rot(srcRot[0][0], srcRot[1][0], srcRot[2][0],
  631.                           srcRot[0][1], srcRot[1][1], srcRot[2][1],
  632.                           srcRot[0][2], srcRot[1][2], srcRot[2][2]);
  633.  
  634.         newbone->setOrientation(rot);
  635.         newbone->setPosition(trans);
  636.         newbone->setScale(Ogre::Vector3(scale));
  637.         newbone->setBindingPose();
  638.         newbone->setInitialState();
  639.  
  640.         bone = newbone;
  641.     }
  642.  
  643.     std::vector<NiAVObjectRef> list = node->GetChildren();
  644.     for(size_t i = 0;i < list.size();i++)
  645.     {
  646.         if(list[i]->IsDerivedType(NiNode::TYPE))
  647.             buildBones(skel, StaticCast<NiNode>(list[i]), bone);
  648.     }
  649. }
  650.  
  651.  
  652. struct NIFMeshLoader : public Ogre::ManualResourceLoader {
  653.     void loadResource(Ogre::Resource *resource)
  654.     {
  655.         // Get the mesh and possible skeleton
  656.         Ogre::Mesh *mesh = dynamic_cast<Ogre::Mesh*>(resource);
  657.         OgreAssert(mesh, "Request to load a mesh in a non-mesh resource");
  658.  
  659.         // Look it up
  660.         const Ogre::String &name = mesh->getName();
  661.         size_t atpos = name.rfind('@');
  662.         const Ogre::String &basename = name.substr(0, atpos);
  663.  
  664.         Ogre::ResourceGroupManager &resMgr = Ogre::ResourceGroupManager::getSingleton();
  665.         std::auto_ptr<InStream> stream(new InStream(resMgr.openResource(basename)));
  666.         NiAVObjectRef root = DynamicCast<NiAVObject>(ReadNifTree(*stream.get()));
  667.         stream.reset();
  668.  
  669.         // Handle the node
  670.         findNiTriShape(mesh, name.substr(atpos+1), root);
  671.  
  672.         // Finally, set the bounding value. Just use bogus info right now.
  673.         mesh->_setBounds(Ogre::AxisAlignedBox(-200,-200,-200,200,200,200));
  674.         mesh->_setBoundingSphereRadius(250);
  675.     }
  676. };
  677.  
  678. static void createMeshes(const Ogre::String &fname, const Ogre::String &group, Ogre::MeshManager *meshMgr, std::vector<Ogre::MeshPtr> *meshes, Ogre::Skeleton *skel, std::map<Ogre::String,Ogre::String> *meshbones, NiAVObjectRef obj, NiNodeRef parent=NULL, int flags=0)
  679. {
  680.     flags |= obj->GetFlags();
  681.  
  682.     // Check for extra data
  683.     const std::list<NiExtraDataRef> &e = obj->GetExtraData();
  684.     for(std::list<NiExtraDataRef>::const_iterator iter=e.begin();iter != e.end();iter++)
  685.     {
  686.         // Get the next extra data in the list
  687.         Ogre::LogManager::getSingleton().stream() << "Extra data in "<<obj->GetName()<<" (type "<<(*iter)->GetType().GetTypeName()<<")";
  688.         NiStringExtraDataRef sd;
  689.         NiTextKeyExtraDataRef tk;
  690.         if((sd=DynamicCast<NiStringExtraData>(*iter)) != NULL)
  691.         {
  692.             // String markers may contain important information
  693.             // affecting the entire subtree of this obj
  694.             if(sd->GetData() == "NCO")
  695.             {
  696.                 // No collision. Clear the appropriate flags.
  697.                 flags &= ~(0x02|0x04);
  698.             }
  699.             else if(sd->GetData() == "MRK")
  700.             {
  701.                 // Marker objects. These are only visible in the
  702.                 // editor. Until and unless we add an editor component to
  703.                 // the engine, just skip this entire branch.
  704.                 return;
  705.             }
  706.             else
  707.                 Ogre::LogManager::getSingleton().stream() << "Unknown extra data string \""<<sd->GetData()<<"\"";
  708.         }
  709.         else if((tk=DynamicCast<NiTextKeyExtraData>(*iter)) != NULL)
  710.         {
  711.             // Animation and soundgen information is apparently stored in an array
  712.             // like this. The string key is specified as like "Idle: Start",
  713.             // "SwimWalkLeft: Loop Stop", and "Soundgen: Land", and the float value
  714.             // is the time in seconds along the animation track that corresponds
  715.             // with the action. There can be more than one text key action per
  716.             // pair, separated by a newline. Need to look into why some text keys
  717.             // are empty, though, and some have an errant newline at the end. A
  718.             // blank action may mean something, or it may be left-over junk.
  719.             std::vector<Key<std::string> > keys = tk->GetKeys();
  720.             for(size_t i = 0;i < keys.size();i++)
  721.             {
  722.                 Ogre::LogManager::getSingleton().stream() << "\""<<keys[i].data<<"\" = "<<keys[i].time;
  723.             }
  724.         }
  725.         else
  726.             Ogre::LogManager::getSingleton().stream() << "Unhandled extra data type: "<<(*iter)->GetType().GetTypeName();
  727.     }
  728.  
  729.     if(obj->IsSameType(NiTriShape::TYPE))
  730.     {
  731.         static NIFMeshLoader loader;
  732.         Ogre::MeshPtr mesh;
  733.         if(!(flags&0x01))
  734.         {
  735.             mesh = meshMgr->createManual(fname+"@"+obj->GetName(), group, &loader);
  736.             if(skel && StaticCast<NiTriShape>(obj)->GetSkinInstance())
  737.                 mesh->setSkeletonName(skel->getName());
  738.             (*meshbones)[mesh->getName()] = parent->GetName();
  739.             meshes->push_back(mesh);
  740.         }
  741.     }
  742.     else if(!obj->IsSameType(NiNode::TYPE))
  743.         Ogre::LogManager::getSingleton().stream() << "Unhandled object type "<<obj->GetType().GetTypeName();
  744.  
  745.     if(obj->IsDerivedType(NiNode::TYPE))
  746.     {
  747.         // For NiNodes, loop through children
  748.         NiNodeRef node = StaticCast<NiNode>(obj);
  749.         std::vector<NiAVObjectRef> list = node->GetChildren();
  750.         for(size_t i = 0;i < list.size();i++)
  751.             createMeshes(fname, group, meshMgr, meshes, skel, meshbones, list[i], node, flags);
  752.     }
  753. }
  754.  
  755. struct NIFSkeletonLoader : public Ogre::ManualResourceLoader {
  756.     void loadResource(Ogre::Resource *resource)
  757.     {
  758.         // Get the mesh and possible skeleton
  759.         Ogre::Skeleton *skel = dynamic_cast<Ogre::Skeleton*>(resource);
  760.         OgreAssert(skel, "Request to load a skeleton in a non-skeleton resource");
  761.  
  762.         const Ogre::String &name = skel->getName();
  763.  
  764.         Ogre::ResourceGroupManager &resMgr = Ogre::ResourceGroupManager::getSingleton();
  765.         std::auto_ptr<InStream> stream(new InStream(resMgr.openResource(name)));
  766.         NiNodeRef root = DynamicCast<NiNode>(ReadNifTree(*stream.get()));
  767.         stream.reset();
  768.  
  769.         // Handle the node
  770.         buildBones(skel, root);
  771.     }
  772. };
  773.  
  774. static bool hasRootBone(NiNodeRef node)
  775. {
  776.     if(node->IsSkeletonRoot())
  777.         return true;
  778.  
  779.     std::vector<NiAVObjectRef> list = node->GetChildren();
  780.     size_t n = list.size();
  781.     for(size_t i = 0;i < n;i++)
  782.     {
  783.         if(list[i]->IsDerivedType(NiNode::TYPE))
  784.         {
  785.             if(hasRootBone(StaticCast<NiNode>(list[i])))
  786.                 return true;
  787.         }
  788.     }
  789.     return false;
  790. }
  791.  
  792.  
  793. void NIFObject::create(const Ogre::String &fname, const Ogre::String &group,
  794.                        std::vector<Ogre::MeshPtr> *meshes, Ogre::SkeletonPtr *skel,
  795.                        std::map<Ogre::String,Ogre::String> *meshbones)
  796. {
  797.     Ogre::MeshManager *meshMgr = Ogre::MeshManager::getSingletonPtr();
  798.     Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr();
  799.     Ogre::ResourceGroupManager *resMgr = Ogre::ResourceGroupManager::getSingletonPtr();
  800.  
  801.     meshes->clear();
  802.     skel->setNull();
  803.  
  804.     std::auto_ptr<InStream> stream(new InStream(resMgr->openResource(fname)));
  805.     NiObjectRef root = ReadNifTree(*stream.get());
  806.     stream.reset();
  807.  
  808.     if(root->IsDerivedType(NiNode::TYPE) && hasRootBone(StaticCast<NiNode>(root)))
  809.     {
  810.         if((*skel=skelMgr->getByName(fname)).isNull())
  811.         {
  812.             static NIFSkeletonLoader loader;
  813.             *skel = skelMgr->create(fname, group, true, &loader);
  814.         }
  815.     }
  816.  
  817.     if(root->IsDerivedType(NiAVObject::TYPE))
  818.         createMeshes(fname, group, meshMgr, meshes, skel->get(), meshbones, StaticCast<NiAVObject>(root));
  819. }
  820.  
  821. /* Comparitor to help sort Key<> vectors */
  822. template<class T>
  823. struct KeyTimeSort
  824. {
  825.     bool operator()(const Key<T> &lhs, const Key<T> &rhs) const
  826.     { return lhs.time < rhs.time; }
  827. };
  828.  
  829. void NIFObject::create(const Ogre::String &fname, Ogre::SkeletonPtr skel,
  830.                        Ogre::Animation **anim)
  831. {
  832.     Ogre::ResourceGroupManager &resMgr = Ogre::ResourceGroupManager::getSingleton();
  833.  
  834.     std::auto_ptr<InStream> stream(new InStream(resMgr.openResource(fname)));
  835.     NiObjectRef root = ReadNifTree(*stream.get());
  836.     stream.reset();
  837.  
  838.     skel->load();
  839.  
  840.     // Get the animation
  841.     if(root->IsSameType(NiSequenceStreamHelper::TYPE))
  842.     {
  843.         NiSequenceStreamHelperRef seq = StaticCast<NiSequenceStreamHelper>(root);
  844.         std::vector< Key<std::string> > animkeys;
  845.         std::vector<Ogre::String> targetnames;
  846.         float maxtime = 0.0f;
  847.  
  848.         const std::list<NiExtraDataRef> &e = seq->GetExtraData();
  849.         for(std::list<NiExtraDataRef>::const_iterator iter=e.begin();iter != e.end();iter++)
  850.         {
  851.             Ogre::LogManager::getSingleton().stream() << "Extra data in \""<<seq->GetName()<<"\" (type "<<(*iter)->GetType().GetTypeName()<<")";
  852.             // Get the bone targets from the extra data
  853.             NiStringExtraDataRef sd;
  854.             NiTextKeyExtraDataRef tk;
  855.             if((sd=DynamicCast<NiStringExtraData>(*iter)) != NULL)
  856.                 targetnames.push_back(sd->GetData());
  857.             else if((tk=DynamicCast<NiTextKeyExtraData>(*iter)) != NULL)
  858.             {
  859.                 animkeys = tk->GetKeys();
  860.                 std::sort(animkeys.begin(), animkeys.end(), KeyTimeSort<std::string>());
  861.                 for(size_t i = 0;i < animkeys.size();i++)
  862.                     Ogre::LogManager::getSingleton().stream() << "\""<<animkeys[i].data<<"\" = "<<animkeys[i].time;
  863.             }
  864.             else
  865.                 Ogre::LogManager::getSingleton().stream() << "Unhandled extra data type: "<<(*iter)->GetType().GetTypeName();
  866.         }
  867.  
  868.         std::list<NiTimeControllerRef> ctrls = seq->GetControllers();
  869.         if(!targetnames.empty() && ctrls.size() != targetnames.size())
  870.             OGRE_EXCEPT(Ogre::Exception::ERR_RT_ASSERTION_FAILED, "Bad targetnames size", __PRETTY_FUNCTION__);
  871.  
  872.         std::list<NiTimeControllerRef>::const_iterator ctrl;
  873.         size_t idx = 0;
  874.         for(ctrl = ctrls.begin();ctrl != ctrls.end();ctrl++,idx++)
  875.         {
  876.             maxtime = std::max(maxtime, (*ctrl)->GetStopTime());
  877.             /* Find the bone target this track affects (.kf animations appear to
  878.              * store the targets using the bone names in the sequence's extra
  879.              * data, while .nif animations use the controller's target ref). */
  880.             NiObjectNETRef target = (*ctrl)->GetTarget();
  881.             if(target)
  882.                 targetnames[idx] = target->GetName();
  883.         }
  884.  
  885.         *anim = skel->createAnimation(seq->GetName(), maxtime);
  886.         /* HACK: Pre-create the node tracks by matching the track IDs with the
  887.          * bone IDs. Otherwise, Ogre animates the wrong bones. */
  888.         size_t bonecount = skel->getNumBones();
  889.         for(size_t i = 0;i < bonecount;i++)
  890.             (*anim)->createNodeTrack(i, skel->getBone(i));
  891. #if 1
  892.         idx = 0;
  893.         for(ctrl = ctrls.begin();ctrl != ctrls.end();ctrl++,idx++)
  894.         {
  895.             if(!(*ctrl)->IsSameType(NiKeyframeController::TYPE))
  896.             {
  897.                 std::cout <<"Unhandled controller: "<<(*ctrl)->GetType().GetTypeName()<< std::endl;
  898.                 continue;
  899.             }
  900.             NiKeyframeControllerRef kfc = StaticCast<NiKeyframeController>(*ctrl);
  901.             NiKeyframeDataRef kf = kfc->GetData();
  902.             kf->NormalizeKeys(kfc->GetPhase(), kfc->GetFrequency());
  903.  
  904.             /* Get the keyframes and make sure they're sorted first to last */
  905.             std::vector< Key<Quaternion> > quatkeys = kf->GetQuatRotateKeys();
  906.             std::vector< Key<Vector3> > trankeys = kf->GetTranslateKeys();
  907.             std::vector< Key<float> > scalekeys = kf->GetScaleKeys();
  908.             std::sort(quatkeys.begin(), quatkeys.end(), KeyTimeSort<Quaternion>());
  909.             std::sort(trankeys.begin(), trankeys.end(), KeyTimeSort<Vector3>());
  910.             std::sort(scalekeys.begin(), scalekeys.end(), KeyTimeSort<float>());
  911.  
  912.             std::vector< Key<Quaternion> >::const_iterator quatiter = quatkeys.begin();
  913.             std::vector< Key<Vector3> >::const_iterator traniter = trankeys.begin();
  914.             std::vector< Key<float> >::const_iterator scaleiter = scalekeys.begin();
  915.  
  916.             Ogre::Bone *bone = skel->getBone(targetnames[idx]);
  917.             const Ogre::Quaternion startquat = bone->getInitialOrientation();
  918.             const Ogre::Vector3 starttrans = bone->getInitialPosition();
  919.             const Ogre::Vector3 startscale = bone->getInitialScale();
  920.             Ogre::NodeAnimationTrack *nodetrack = (*anim)->getNodeTrack(bone->getHandle());
  921.  
  922.             Ogre::Quaternion lastquat, curquat;
  923.             Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f);
  924.             Ogre::Vector3 lastscale(1.0f), curscale(1.0f);
  925.             if(quatiter != quatkeys.end())
  926.                 lastquat = curquat = startquat.Inverse() * ConvertQuaternion(quatiter->data);
  927.             if(traniter != trankeys.end())
  928.                 lasttrans = curtrans = ConvertVector3(traniter->data) - starttrans;
  929.             if(scaleiter != scalekeys.end())
  930.                 lastscale = curscale = Ogre::Vector3(scaleiter->data) / startscale;
  931.             bool didlast = false;
  932.             while(!didlast)
  933.             {
  934.                 float curtime = kfc->GetStopTime();
  935.                 if(quatiter != quatkeys.end())
  936.                     curtime = std::min(curtime, quatiter->time);
  937.                 if(traniter != trankeys.end())
  938.                     curtime = std::min(curtime, traniter->time);
  939.                 if(scaleiter != scalekeys.end())
  940.                     curtime = std::min(curtime, scaleiter->time);
  941.  
  942.                 curtime = std::max(curtime, kfc->GetStartTime());
  943.                 if(curtime >= kfc->GetStopTime())
  944.                 {
  945.                     didlast = true;
  946.                     curtime = kfc->GetStopTime();
  947.                 }
  948.  
  949.                 // Get the latest quaternion, translation, and scale for the
  950.                 // current time
  951.                 while(quatiter != quatkeys.end() && curtime >= quatiter->time)
  952.                 {
  953.                     lastquat = curquat;
  954.                     curquat = startquat.Inverse() * ConvertQuaternion(quatiter->data);
  955.                     quatiter++;
  956.                 }
  957.                 while(traniter != trankeys.end() && curtime >= traniter->time)
  958.                 {
  959.                     lasttrans = curtrans;
  960.                     curtrans = ConvertVector3(traniter->data) - starttrans;
  961.                     traniter++;
  962.                 }
  963.                 while(scaleiter != scalekeys.end() && curtime >= scaleiter->time)
  964.                 {
  965.                     lastscale = curscale;
  966.                     curscale = Ogre::Vector3(scaleiter->data) / startscale;
  967.                     scaleiter++;
  968.                 }
  969.  
  970.  
  971.                 Ogre::TransformKeyFrame *kframe;
  972.                 kframe = nodetrack->createNodeKeyFrame(curtime);
  973.                 if(quatiter == quatkeys.end() || quatiter == quatkeys.begin())
  974.                     kframe->setRotation(curquat);
  975.                 else
  976.                 {
  977.                     std::vector< Key<Quaternion> >::const_iterator last = quatiter-1;
  978.                     float diff = (curtime-last->time) / (quatiter->time-last->time);
  979.                     kframe->setRotation(Ogre::Quaternion::Slerp(diff, lastquat, curquat));
  980.                 }
  981.                 if(traniter == trankeys.end() || traniter == trankeys.begin())
  982.                     kframe->setTranslate(curtrans);
  983.                 else
  984.                 {
  985.                     std::vector< Key<Vector3> >::const_iterator last = traniter-1;
  986.                     float diff = (curtime-last->time) / (traniter->time-last->time);
  987.                     kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff));
  988.                 }
  989.                 if(scaleiter == scalekeys.end() || scaleiter == scalekeys.begin())
  990.                     kframe->setScale(curscale);
  991.                 else
  992.                 {
  993.                     std::vector< Key<float> >::const_iterator last = scaleiter-1;
  994.                     float diff = (curtime-last->time) / (scaleiter->time-last->time);
  995.                     kframe->setScale(lastscale + ((curscale-lastscale)*diff));
  996.                 }
  997.             }
  998.         }
  999.  
  1000.         (*anim)->optimise();
  1001. #endif
  1002.     }
  1003.     else
  1004.         std::cout <<"Unhandled animation type: "<<root->GetType().GetTypeName()<< std::endl;
  1005. }
Add Comment
Please, Sign In to add comment