[6] | 1 | /**************************************************************** |
---|
| 2 | Thanks to Bandures for the particle exporter |
---|
| 3 | ****************************************************************/ |
---|
| 4 | |
---|
| 5 | /********************************************************************************* |
---|
| 6 | * * |
---|
| 7 | * This program is free software; you can redistribute it and/or modify * |
---|
| 8 | * it under the terms of the GNU Lesser General Public License as published by * |
---|
| 9 | * the Free Software Foundation; either version 2 of the License, or * |
---|
| 10 | * (at your option) any later version. * |
---|
| 11 | * * |
---|
| 12 | **********************************************************************************/ |
---|
| 13 | |
---|
| 14 | #include "particles.h" |
---|
| 15 | |
---|
| 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 17 | namespace OgreMayaExporter |
---|
| 18 | { |
---|
| 19 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 20 | const float FP_2PI = 6.28318531f; |
---|
| 21 | static float FP_MINDELTA = 0.005f; |
---|
| 22 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 23 | inline float ToRadians( float fD ) { return fD * ( FP_2PI / 360.f ); } |
---|
| 24 | inline float ToDegrees( float fR ) { return fR * ( 360.f / FP_2PI ); } |
---|
| 25 | template<class T> void DropSame( const std::vector<T> &values, int nBeginTime, TKeyTrack<T> *pRes ); |
---|
| 26 | template<class T> void MakeLinearSpline( const std::vector<T> &values, int nBeginTime, float fEpsilon, TKeyTrack<T> *pRes ); |
---|
| 27 | template<class T> void writeTrackToXML( std::ofstream &outStream, const TKeyTrack<T> &dataTrack, const std::string &name ); |
---|
| 28 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 29 | // Particles |
---|
| 30 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 31 | Particles::Particles(): |
---|
| 32 | nFrames(0) |
---|
| 33 | { |
---|
| 34 | } |
---|
| 35 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 36 | Particles::~Particles() |
---|
| 37 | { |
---|
| 38 | clear(); |
---|
| 39 | } |
---|
| 40 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 41 | MStatus Particles::load( MDagPath& dagPath, ParamList& params ) |
---|
| 42 | { |
---|
| 43 | int nMaxFrame, nMinFrame; |
---|
| 44 | MGlobal::executeCommand( "playbackOptions -q -max", nMaxFrame ); |
---|
| 45 | MGlobal::executeCommand( "playbackOptions -q -min", nMinFrame ); |
---|
| 46 | if ( nMinFrame > 0 ) |
---|
| 47 | nMinFrame = 0; |
---|
| 48 | |
---|
| 49 | for ( int nFrame = nMinFrame; nFrame <= nMaxFrame; ++nFrame ) |
---|
| 50 | ExportFrame( dagPath, nFrame ); |
---|
| 51 | |
---|
| 52 | FinalizeData( nMinFrame, nMaxFrame ); |
---|
| 53 | return MS::kSuccess; |
---|
| 54 | } |
---|
| 55 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 56 | MStatus Particles::writeToXML( ParamList& params ) |
---|
| 57 | { |
---|
| 58 | params.outParticles << "<particles frames=\"" << nFrames << "\" tracks=\"" << particleTracks.size() << "\" >\n"; |
---|
| 59 | for ( uint nTemp = 0; nTemp < particleTracks.size(); ++nTemp ) |
---|
| 60 | { |
---|
| 61 | const SParticle &particle = particleTracks[nTemp]; |
---|
| 62 | params.outParticles << "\t<particle startFrame=\"" << particle.nStartTime << "\" endFrame=\"" << particle.nEndTime << "\" >\n"; |
---|
| 63 | writeTrackToXML( params.outParticles, particle.pos, "position" ); |
---|
| 64 | writeTrackToXML( params.outParticles, particle.rotation, "rotation" ); |
---|
| 65 | writeTrackToXML( params.outParticles, particle.scale, "scale" ); |
---|
| 66 | writeTrackToXML( params.outParticles, particle.color, "color" ); |
---|
| 67 | writeTrackToXML( params.outParticles, particle.sprite, "sprite" ); |
---|
| 68 | params.outParticles << "\t</particle>\n"; |
---|
| 69 | } |
---|
| 70 | params.outParticles << "</particles>\n"; |
---|
| 71 | return MS::kSuccess; |
---|
| 72 | } |
---|
| 73 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 74 | void Particles::clear() |
---|
| 75 | { |
---|
| 76 | } |
---|
| 77 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 78 | MStatus Particles::ExportFrame( MDagPath &dagPath, int nFrame ) |
---|
| 79 | { |
---|
| 80 | MGlobal::viewFrame( nFrame ); |
---|
| 81 | |
---|
| 82 | MStatus retStatus; |
---|
| 83 | MFnDagNode dagNode( dagPath ); |
---|
| 84 | //// |
---|
| 85 | int nParticles = 0; |
---|
| 86 | MPlug countPlug = dagNode.findPlug( MString( "count" ), &retStatus ); |
---|
| 87 | retStatus = countPlug.getValue( nParticles ); |
---|
| 88 | if ( nParticles <= 0 ) |
---|
| 89 | return MS::kFailure; |
---|
| 90 | //// |
---|
| 91 | std::vector<int> idIndex( nParticles ); |
---|
| 92 | std::vector<int> sortedId( nParticles ); |
---|
| 93 | std::vector<SParticleData> particlesFrame( nParticles ); |
---|
| 94 | //// |
---|
| 95 | MObject tempObj; |
---|
| 96 | MPlug mappingPlug = dagNode.findPlug( MString( "idMapping" ), &retStatus ); |
---|
| 97 | //// |
---|
| 98 | MPlug idPlug = mappingPlug.child( 0 ); |
---|
| 99 | retStatus = idPlug.getValue( tempObj ); |
---|
| 100 | MFnIntArrayData sSortedIDArray( tempObj, &retStatus ); |
---|
| 101 | for ( int nTemp = 0; nTemp < nParticles; ++nTemp ) |
---|
| 102 | sortedId[nTemp] = sSortedIDArray[nTemp]; |
---|
| 103 | //// |
---|
| 104 | MPlug indexPlug = mappingPlug.child( 1 ); |
---|
| 105 | retStatus = indexPlug.getValue( tempObj ); |
---|
| 106 | MFnIntArrayData idIndexArray( tempObj, &retStatus ); |
---|
| 107 | for ( int nTemp = 0; nTemp < nParticles; ++nTemp ) |
---|
| 108 | idIndex[nTemp] = idIndexArray[nTemp]; |
---|
| 109 | //// Position |
---|
| 110 | MPlug posPlug = dagNode.findPlug( MString( "worldPosition" ), &retStatus ); |
---|
| 111 | retStatus = posPlug.getValue( tempObj ); |
---|
| 112 | MFnVectorArrayData posData( tempObj, &retStatus ); |
---|
| 113 | for ( int nTemp = 0; nTemp < nParticles; ++nTemp ) |
---|
| 114 | { |
---|
| 115 | SParticleData &particle = particlesFrame[nTemp]; |
---|
| 116 | particle.nFrame = nFrame; |
---|
| 117 | particle.pos.x = (float)posData[idIndex[nTemp]].x; |
---|
| 118 | particle.pos.y = (float)posData[idIndex[nTemp]].y; |
---|
| 119 | particle.pos.z = (float)posData[idIndex[nTemp]].z; |
---|
| 120 | } |
---|
| 121 | //// Rotation |
---|
| 122 | MPlug rotPlug = dagNode.findPlug( MString( "spriteTwistPP" ), &retStatus ); |
---|
| 123 | if ( retStatus == MS::kSuccess ) |
---|
| 124 | { |
---|
| 125 | retStatus = rotPlug.getValue( tempObj ); |
---|
| 126 | MFnDoubleArrayData rotPlug( tempObj, &retStatus ); |
---|
| 127 | for ( int nTemp = 0; nTemp < nParticles; ++nTemp ) |
---|
| 128 | particlesFrame[nTemp].fRotation = ToRadians( (float)rotPlug[idIndex[nTemp]] ); |
---|
| 129 | } |
---|
| 130 | //// ScaleX |
---|
| 131 | MPlug scaleXPlug = dagNode.findPlug( MString( "spriteScaleXPP" ), &retStatus ); |
---|
| 132 | if ( retStatus == MS::kSuccess ) |
---|
| 133 | { |
---|
| 134 | retStatus = scaleXPlug.getValue( tempObj ); |
---|
| 135 | MFnDoubleArrayData scaleX( tempObj, &retStatus ); |
---|
| 136 | for ( int nTemp = 0; nTemp < nParticles; ++nTemp ) |
---|
| 137 | particlesFrame[nTemp].scale.x = float( scaleX[idIndex[nTemp]] ); |
---|
| 138 | } |
---|
| 139 | //// ScaleY |
---|
| 140 | MPlug scaleYPlug = dagNode.findPlug( MString( "spriteScaleYPP" ), &retStatus ); |
---|
| 141 | if ( retStatus == MS::kSuccess ) |
---|
| 142 | { |
---|
| 143 | retStatus = scaleYPlug.getValue( tempObj ); |
---|
| 144 | MFnDoubleArrayData scaleY( tempObj, &retStatus ); |
---|
| 145 | for ( int nTemp = 0; nTemp < nParticles; ++nTemp ) |
---|
| 146 | particlesFrame[nTemp].scale.y = float( scaleY[idIndex[nTemp]] ); |
---|
| 147 | } |
---|
| 148 | //// Sprite |
---|
| 149 | MPlug spritePlug = dagNode.findPlug( MString( "spriteNumPP" ), &retStatus ); |
---|
| 150 | if ( retStatus == MS::kSuccess ) |
---|
| 151 | { |
---|
| 152 | retStatus = spritePlug.getValue( tempObj ); |
---|
| 153 | MFnDoubleArrayData sprite( tempObj, &retStatus ); |
---|
| 154 | for ( int nTemp = 0; nTemp < nParticles; ++nTemp ) |
---|
| 155 | particlesFrame[nTemp].nSprite = int( sprite[idIndex[nTemp]] - 1 ); |
---|
| 156 | } |
---|
| 157 | //// Color |
---|
| 158 | MPlug colorPlug = dagNode.findPlug( MString( "rgbPP" ), &retStatus ); |
---|
| 159 | if ( retStatus == MS::kSuccess ) |
---|
| 160 | { |
---|
| 161 | retStatus = colorPlug.getValue( tempObj ); |
---|
| 162 | MFnVectorArrayData rgbData( tempObj, &retStatus ); |
---|
| 163 | for ( int nTemp = 0; nTemp < nParticles; ++nTemp ) |
---|
| 164 | { |
---|
| 165 | particlesFrame[nTemp].color.r = float( rgbData[idIndex[nTemp]].x ); |
---|
| 166 | particlesFrame[nTemp].color.g = float( rgbData[idIndex[nTemp]].y ); |
---|
| 167 | particlesFrame[nTemp].color.b = float( rgbData[idIndex[nTemp]].z ); |
---|
| 168 | } |
---|
| 169 | } |
---|
| 170 | //// Opacity |
---|
| 171 | MPlug alphaPlug = dagNode.findPlug( MString( "opacityPP" ), &retStatus ); |
---|
| 172 | if ( retStatus == MS::kSuccess ) |
---|
| 173 | { |
---|
| 174 | retStatus = alphaPlug.getValue( tempObj ); |
---|
| 175 | MFnDoubleArrayData alphaData( tempObj, &retStatus ); |
---|
| 176 | for ( int nTemp = 0; nTemp < nParticles; ++nTemp ) |
---|
| 177 | particlesFrame[nTemp].color.a = float( alphaData[idIndex[nTemp]] ); |
---|
| 178 | } |
---|
| 179 | |
---|
| 180 | for ( int nTemp = 0; nTemp < nParticles; ++nTemp ) |
---|
| 181 | data[sortedId[nTemp]].push_back( particlesFrame[nTemp] ); |
---|
| 182 | |
---|
| 183 | return MS::kSuccess; |
---|
| 184 | } |
---|
| 185 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 186 | MStatus Particles::FinalizeData( int nMinFrame, int nMaxFrame ) |
---|
| 187 | { |
---|
| 188 | nFrames = nMaxFrame - nMinFrame + 1; |
---|
| 189 | particleTracks.resize( data.size() ); |
---|
| 190 | |
---|
| 191 | int nTemp = 0; |
---|
| 192 | for ( CParticlesData::const_iterator iTemp = data.begin(); iTemp != data.end(); ++iTemp, ++nTemp ) |
---|
| 193 | { |
---|
| 194 | SParticle &particle = particleTracks[nTemp]; |
---|
| 195 | //// |
---|
| 196 | const CParticlesTrack &particlesTrack = iTemp->second; |
---|
| 197 | int nEndFrame = particlesTrack.back().nFrame; |
---|
| 198 | int nStartFrame = particlesTrack.front().nFrame; |
---|
| 199 | int nFrames = nEndFrame - nStartFrame + 1; |
---|
| 200 | //// |
---|
| 201 | if ( nFrames != particlesTrack.size() ) |
---|
| 202 | { |
---|
| 203 | std::cout << "ERROR: particle dosn't exist in some frames (unsupported)!\n"; |
---|
| 204 | std::cout.flush(); |
---|
| 205 | return MS::kFailure; |
---|
| 206 | } |
---|
| 207 | //// |
---|
| 208 | int nBeginTime = nStartFrame; |
---|
| 209 | particle.nEndTime = nEndFrame; |
---|
| 210 | particle.nStartTime = nStartFrame; |
---|
| 211 | //// |
---|
| 212 | std::vector<SPos> tmpPos( nFrames ); |
---|
| 213 | for ( int nTemp = 0; nTemp < nFrames; ++nTemp ) |
---|
| 214 | tmpPos[nTemp] = particlesTrack[nTemp].pos; |
---|
| 215 | MakeLinearSpline( tmpPos, nBeginTime, FP_MINDELTA, &particle.pos ); |
---|
| 216 | //// |
---|
| 217 | std::vector<float> tmpRot( nFrames ); |
---|
| 218 | for ( int nTemp = 0; nTemp < nFrames; ++nTemp ) |
---|
| 219 | tmpRot[nTemp] = particlesTrack[nTemp].fRotation; |
---|
| 220 | MakeLinearSpline( tmpRot, nBeginTime, FP_MINDELTA, &particle.rotation ); |
---|
| 221 | //// |
---|
| 222 | std::vector<SScale> tmpScale( nFrames ); |
---|
| 223 | for ( int nTemp = 0; nTemp < nFrames; ++nTemp ) |
---|
| 224 | tmpScale[nTemp] = particlesTrack[nTemp].scale; |
---|
| 225 | MakeLinearSpline( tmpScale, nBeginTime, FP_MINDELTA, &particle.scale ); |
---|
| 226 | //// |
---|
| 227 | std::vector<SColor> tmpColor( nFrames ); |
---|
| 228 | for ( int nTemp = 0; nTemp < nFrames; ++nTemp ) |
---|
| 229 | tmpColor[nTemp] = particlesTrack[nTemp].color; |
---|
| 230 | MakeLinearSpline( tmpColor, nBeginTime, FP_MINDELTA, &particle.color ); |
---|
| 231 | //// |
---|
| 232 | std::vector<int> tmpSprite( nFrames ); |
---|
| 233 | for ( int nTemp = 0; nTemp < nFrames; ++nTemp ) |
---|
| 234 | tmpSprite[nTemp] = particlesTrack[nTemp].nSprite; |
---|
| 235 | DropSame( tmpSprite, nBeginTime, &particle.sprite ); |
---|
| 236 | } |
---|
| 237 | |
---|
| 238 | return MS::kSuccess; |
---|
| 239 | } |
---|
| 240 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 241 | template<class T> |
---|
| 242 | bool CanDropValue( const T &value, const T &prevVal, const T &nextVal, int nDelta, int nRange, float fEpsilon ) |
---|
| 243 | { |
---|
| 244 | T resVal; |
---|
| 245 | float fCoeff = float( nDelta ) / nRange; |
---|
| 246 | Interpolate( prevVal, nextVal, fCoeff, &resVal ); |
---|
| 247 | if ( fabs( resVal - value ) < fEpsilon ) |
---|
| 248 | return true; |
---|
| 249 | //// |
---|
| 250 | return false; |
---|
| 251 | } |
---|
| 252 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 253 | template<class T> |
---|
| 254 | void MakeLinearSpline( const std::vector<T> &values, int nBeginTime, float fEpsilon, TKeyTrack<T> *pRes ) |
---|
| 255 | { |
---|
| 256 | if ( values.size() == 0 ) |
---|
| 257 | return; |
---|
| 258 | //// |
---|
| 259 | TKey<T> startKey; |
---|
| 260 | startKey.nTime = nBeginTime; |
---|
| 261 | startKey.value = values.front(); |
---|
| 262 | pRes->keys.push_back( startKey ); |
---|
| 263 | if ( values.size() == 1 ) |
---|
| 264 | return; |
---|
| 265 | //// |
---|
| 266 | uint nIndex = 0; |
---|
| 267 | uint nPrevIndex = 0; |
---|
| 268 | while( nIndex < values.size() - 1 ) |
---|
| 269 | { |
---|
| 270 | if ( !CanDropValue<T>( values[nIndex], values[nPrevIndex], values[nIndex + 1], nIndex - nPrevIndex, nIndex - nPrevIndex + 1, fEpsilon ) ) |
---|
| 271 | { |
---|
| 272 | nPrevIndex = nIndex; |
---|
| 273 | TKey<T> resKey; |
---|
| 274 | resKey.nTime = nBeginTime + nIndex; |
---|
| 275 | resKey.value = values[nIndex]; |
---|
| 276 | pRes->keys.push_back( resKey ); |
---|
| 277 | } |
---|
| 278 | //// |
---|
| 279 | nIndex++; |
---|
| 280 | } |
---|
| 281 | //// |
---|
| 282 | TKey<T> endKey; |
---|
| 283 | endKey.nTime = nBeginTime + values.size() - 1; |
---|
| 284 | endKey.value = values.back(); |
---|
| 285 | pRes->keys.push_back( endKey ); |
---|
| 286 | } |
---|
| 287 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 288 | template<class T> |
---|
| 289 | void DropSame( const std::vector<T> &values, int nBeginTime, TKeyTrack<T> *pRes ) |
---|
| 290 | { |
---|
| 291 | if ( values.size() == 0 ) |
---|
| 292 | return; |
---|
| 293 | //// |
---|
| 294 | TKey<T> startKey; |
---|
| 295 | startKey.nTime = nBeginTime; |
---|
| 296 | startKey.value = values.front(); |
---|
| 297 | pRes->keys.push_back( startKey ); |
---|
| 298 | if ( values.size() == 1 ) |
---|
| 299 | return; |
---|
| 300 | //// |
---|
| 301 | T nCurrent = values.front(); |
---|
| 302 | TKey<T> curKey; |
---|
| 303 | for ( uint nTemp = 1; nTemp < values.size() - 1; ++nTemp ) |
---|
| 304 | { |
---|
| 305 | if ( values[nTemp] != nCurrent ) |
---|
| 306 | { |
---|
| 307 | curKey.nTime = nBeginTime + nTemp; |
---|
| 308 | curKey.value = values[nTemp]; |
---|
| 309 | pRes->keys.push_back( curKey ); |
---|
| 310 | //// |
---|
| 311 | nCurrent = values[nTemp]; |
---|
| 312 | } |
---|
| 313 | } |
---|
| 314 | //// |
---|
| 315 | TKey<T> endKey; |
---|
| 316 | endKey.nTime = nBeginTime + values.size() - 1; |
---|
| 317 | endKey.value = values.back(); |
---|
| 318 | pRes->keys.push_back( endKey ); |
---|
| 319 | } |
---|
| 320 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 321 | template<class T> |
---|
| 322 | void writeKeyToXML( std::ofstream &outStream, const TKey<T> &data ) |
---|
| 323 | { |
---|
| 324 | outStream << "\t\t\t<key time=\"" << data.nTime << "\" value=\"" << data.value << "\"/>\n"; |
---|
| 325 | } |
---|
| 326 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 327 | void writeKeyToXML( std::ofstream &outStream, const TKey<SPos> &data ) |
---|
| 328 | { |
---|
| 329 | outStream << "\t\t\t<key time=\"" << data.nTime << "\" x=\"" << data.value.x << "\" y=\"" << data.value.y << "\" z=\"" << data.value.z << "\"/>\n"; |
---|
| 330 | } |
---|
| 331 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 332 | void writeKeyToXML( std::ofstream &outStream, const TKey<SColor> &data ) |
---|
| 333 | { |
---|
| 334 | outStream << "\t\t\t<key time=\"" << data.nTime << "\" r=\"" << data.value.x << "\" g=\"" << data.value.y << "\" b=\"" << data.value.z << "\" a=\"" << data.value.a << "\"/>\n"; |
---|
| 335 | } |
---|
| 336 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 337 | void writeKeyToXML( std::ofstream &outStream, const TKey<SScale> &data ) |
---|
| 338 | { |
---|
| 339 | outStream << "\t\t\t<key time=\"" << data.nTime << "\" x=\"" << data.value.x << "\" y=\"" << data.value.y << "\"/>\n"; |
---|
| 340 | } |
---|
| 341 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 342 | template<class T> |
---|
| 343 | void writeTrackToXML( std::ofstream &outStream, const TKeyTrack<T> &dataTrack, const std::string &name ) |
---|
| 344 | { |
---|
| 345 | outStream << "\t\t<" << name.c_str() << " keys=\"" << dataTrack.keys.size() << "\" >\n"; |
---|
| 346 | for ( uint nTemp = 0; nTemp < dataTrack.keys.size(); ++nTemp ) |
---|
| 347 | writeKeyToXML( outStream, dataTrack.keys[nTemp] ); |
---|
| 348 | outStream << "\t\t</" << name.c_str() << ">\n"; |
---|
| 349 | } |
---|
| 350 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 351 | } // NAMESPACE |
---|
| 352 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|