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