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 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
---|