1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2015-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "nel/gui/interface_anim.h"
24 #include "nel/gui/widget_manager.h"
25 #include "nel/gui/interface_expr.h"
26 #include "nel/misc/xml_auto_ptr.h"
27 #include "nel/gui/action_handler.h"
29 // ----------------------------------------------------------------------------
32 using namespace NLMISC
;
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
44 CInterfaceTrack::CInterfaceTrack()
47 _TrackKeyFramer
= NULL
;
51 // ----------------------------------------------------------------------------
52 CInterfaceTrack::~CInterfaceTrack()
54 delete _TrackKeyFramer
;
57 // ----------------------------------------------------------------------------
58 bool CInterfaceTrack::parse (xmlNodePtr cur
, CInterfaceGroup
*parentGroup
)
62 ptr
= xmlGetProp (cur
, (xmlChar
*)"dynamic");
63 if (ptr
) _Dynamic
= CInterfaceElement::convertBool (ptr
);
65 ptr
= xmlGetProp (cur
, (xmlChar
*)"type");
66 string sTmp
= toLowerAscii(ptr
.str());
69 else if (sTmp
== "bezier")
71 else if (sTmp
== "tcb")
74 nlwarning ("track unknown type : %s, setting linear by default", (const char*)ptr
);
76 ptr
= xmlGetProp (cur
, (xmlChar
*)"target");
79 nlwarning ("no target for track");
84 if (!CInterfaceLink::splitLinkTargets (ptr
.str(), parentGroup
, _Targets
))
86 nlwarning ("no target for track");
90 // Initialize the track
93 case Track_Linear
: _TrackKeyFramer
= UTrackKeyframer::createLinearFloatTrack(); break;
94 case Track_TCB
: _TrackKeyFramer
= UTrackKeyframer::createTCBFloatTrack(); break;
95 case Track_Bezier
: _TrackKeyFramer
= UTrackKeyframer::createBezierFloatTrack(); break;
96 default: nlstop
; break;
106 // Check that this is a key node
107 if ( stricmp((char*)cur
->name
,"key") != 0 )
113 // Read time and value the 2 main key attributes
114 CXMLAutoPtr time
, value
;
115 time
= xmlGetProp (cur
, (xmlChar
*)"time");
116 value
= xmlGetProp (cur
, (xmlChar
*)"value");
119 nlwarning("track key with no time or no value");
126 k
.Value
= (const char*)value
;
127 k
.Time
= (const char*)time
;
128 if (isdigit(k
.Time
[0]) || (k
.Time
[0] == '-'))
131 fromString(k
.Time
, dTime
);
132 k
.Time
= toString(dTime
* CWidgetManager::getInstance()->getSystemOption(CWidgetManager::OptionMulCoefAnim
).getValFloat());
135 // Depending on the type of the track read extra values
143 CXMLAutoPtr inTan
, outTan
, step
;
144 inTan
= xmlGetProp (cur
, (xmlChar
*)"intan");
145 outTan
= xmlGetProp (cur
, (xmlChar
*)"outtan");
146 step
= xmlGetProp (cur
, (xmlChar
*)"step");
148 if (inTan
) k
.InTan
= (const char*)inTan
;
149 if (outTan
) k
.OutTan
= (const char*)outTan
;
150 if (step
) k
.Step
= (const char*)step
;
156 CXMLAutoPtr tension
, continuity
, bias
, easeto
, easefrom
;
157 tension
= xmlGetProp (cur
, (xmlChar
*)"tension");
158 continuity
= xmlGetProp (cur
, (xmlChar
*)"continuity");
159 bias
= xmlGetProp (cur
, (xmlChar
*)"bias");
160 easeto
= xmlGetProp (cur
, (xmlChar
*)"easeto");
161 easefrom
= xmlGetProp (cur
, (xmlChar
*)"easefrom");
163 if (tension
) k
.Tension
= (const char*)tension
;
164 if (continuity
) k
.Continuity
= (const char*)continuity
;
165 if (bias
) k
.Bias
= (const char*)bias
;
166 if (easeto
) k
.EaseTo
= (const char*)easeto
;
167 if (easefrom
) k
.EaseFrom
= (const char*)easefrom
;
170 default: nlstop
; break;
172 _DynKeys
.push_back(k
);
177 else // Static parsing
181 // Check that this is a key node
182 if ( stricmp((char*)cur
->name
,"key") != 0 )
188 // Read time and value the 2 main key attributes
189 CXMLAutoPtr time
, value
;
190 time
= xmlGetProp (cur
, (xmlChar
*)"time");
191 value
= xmlGetProp (cur
, (xmlChar
*)"value");
194 nlwarning("track key with no time or no value");
201 fromString((const char*)time
, fAnimTime
);
202 TAnimationTime animTime
= fAnimTime
* CWidgetManager::getInstance()->getSystemOption(CWidgetManager::OptionMulCoefAnim
).getValFloat();
204 fromString(value
.str(), animValue
);
206 // Depending on the type of the track add the key
211 UTrackKeyframer::UKeyLinearFloat k
;
213 k
.Value
= (float)animValue
;
214 _TrackKeyFramer
->addLinearFloatKey (k
);
220 UTrackKeyframer::UKeyBezierFloat k
;
222 k
.Value
= (float)animValue
;
225 CXMLAutoPtr inTan
, outTan
, step
;
226 inTan
= xmlGetProp (cur
, (xmlChar
*)"intan");
227 outTan
= xmlGetProp (cur
, (xmlChar
*)"outtan");
228 step
= xmlGetProp (cur
, (xmlChar
*)"step");
234 if (inTan
) fromString((const char*)inTan
, k
.TanIn
);
235 if (outTan
) fromString((const char*)outTan
, k
.TanOut
);
236 if (step
) k
.Step
= CInterfaceElement::convertBool(step
);
238 _TrackKeyFramer
->addBezierFloatKey (k
);
244 UTrackKeyframer::UKeyTCBFloat k
;
246 k
.Value
= (float)animValue
;
249 CXMLAutoPtr tension
, continuity
, bias
, easeto
, easefrom
;
250 tension
= xmlGetProp (cur
, (xmlChar
*)"tension");
251 continuity
= xmlGetProp (cur
, (xmlChar
*)"continuity");
252 bias
= xmlGetProp (cur
, (xmlChar
*)"bias");
253 easeto
= xmlGetProp (cur
, (xmlChar
*)"easeto");
254 easefrom
= xmlGetProp (cur
, (xmlChar
*)"easefrom");
262 if (tension
) fromString((const char*)tension
, k
.Tension
);
263 if (continuity
) fromString((const char*)continuity
, k
.Continuity
);
264 if (bias
) fromString((const char*)bias
, k
.Bias
);
265 if (easeto
) fromString((const char*)easeto
, k
.EaseTo
);
266 if (easefrom
) fromString((const char*)easefrom
, k
.EaseFrom
);
268 _TrackKeyFramer
->addTCBFloatKey (k
);
271 default: nlstop
; break;
279 // ----------------------------------------------------------------------------
280 void CInterfaceTrack::update (double currentTime
)
283 UTrack
*pTrack
= dynamic_cast<UTrack
*>(_TrackKeyFramer
);
284 if (pTrack
== NULL
) return;
285 pTrack
->interpolate((TAnimationTime
)currentTime
, currentValue
);
287 // Update the targets
288 CInterfaceExprValue expr
;
289 expr
.setDouble(currentValue
);
290 for (uint i
= 0; i
< _Targets
.size(); ++i
)
291 _Targets
[i
].affect(expr
);
294 // ----------------------------------------------------------------------------
295 void CInterfaceTrack::eval()
297 if (!_Dynamic
) return;
299 if (_TrackKeyFramer
!= NULL
)
300 delete _TrackKeyFramer
;
306 _TrackKeyFramer
= UTrackKeyframer::createLinearFloatTrack();
307 for (uint i
= 0; i
< _DynKeys
.size(); ++i
)
309 SDynKey
&rKey
= _DynKeys
[i
];
310 UTrackKeyframer::UKeyLinearFloat k
;
311 CInterfaceExprValue res
;
312 if (!rKey
.Time
.empty() && CInterfaceExpr::eval(rKey
.Time
, res
))
315 nlwarning ("cannot convert Time to double");
317 k
.Time
= (TAnimationTime
)res
.getDouble();
324 if (!rKey
.Value
.empty() && CInterfaceExpr::eval(rKey
.Value
, res
))
327 nlwarning ("cannot convert Value to double");
329 k
.Value
= (float)res
.getDouble();
336 _TrackKeyFramer
->addLinearFloatKey (k
);
343 _TrackKeyFramer
= UTrackKeyframer::createTCBFloatTrack();
344 for (uint i
= 0; i
< _DynKeys
.size(); ++i
)
346 SDynKey
&rKey
= _DynKeys
[i
];
347 UTrackKeyframer::UKeyTCBFloat k
;
348 CInterfaceExprValue res
;
349 if (!rKey
.Time
.empty() && CInterfaceExpr::eval(rKey
.Time
, res
))
352 nlwarning ("cannot convert Time to double");
354 k
.Time
= (TAnimationTime
)res
.getDouble();
361 if (!rKey
.Value
.empty() && CInterfaceExpr::eval(rKey
.Value
, res
))
364 nlwarning ("cannot convert Value to double");
366 k
.Value
= (float)res
.getDouble();
373 if (!rKey
.Tension
.empty() && CInterfaceExpr::eval(rKey
.Tension
, res
))
376 nlwarning ("cannot convert Tension to double");
378 k
.Tension
= (float)res
.getDouble();
385 if (!rKey
.Continuity
.empty() && CInterfaceExpr::eval(rKey
.Continuity
, res
))
388 nlwarning ("cannot convert Continuity to double");
390 k
.Continuity
= (float)res
.getDouble();
397 if (!rKey
.Bias
.empty() && CInterfaceExpr::eval(rKey
.Bias
, res
))
400 nlwarning ("cannot convert Bias to double");
402 k
.Bias
= (float)res
.getDouble();
409 if (!rKey
.EaseTo
.empty() && CInterfaceExpr::eval(rKey
.EaseTo
, res
))
412 nlwarning ("cannot convert EaseTo to double");
414 k
.EaseTo
= (float)res
.getDouble();
421 if (!rKey
.EaseFrom
.empty() && CInterfaceExpr::eval(rKey
.EaseFrom
, res
))
424 nlwarning ("cannot convert EaseFrom to double");
426 k
.EaseFrom
= (float)res
.getDouble();
433 _TrackKeyFramer
->addTCBFloatKey (k
);
440 _TrackKeyFramer
= UTrackKeyframer::createBezierFloatTrack(); break;
441 for (uint i
= 0; i
< _DynKeys
.size(); ++i
)
443 SDynKey
&rKey
= _DynKeys
[i
];
444 UTrackKeyframer::UKeyBezierFloat k
;
445 CInterfaceExprValue res
;
446 if (!rKey
.Time
.empty() && CInterfaceExpr::eval(rKey
.Time
, res
))
449 nlwarning ("cannot convert Time to double");
451 k
.Time
= (TAnimationTime
)res
.getDouble();
458 if (!rKey
.Value
.empty() && CInterfaceExpr::eval(rKey
.Value
, res
))
461 nlwarning ("cannot convert Value to double");
463 k
.Value
= (float)res
.getDouble();
470 if (!rKey
.InTan
.empty() && CInterfaceExpr::eval(rKey
.InTan
, res
))
473 nlwarning ("cannot convert TanIn to double");
475 k
.TanIn
= (float)res
.getDouble();
482 if (!rKey
.OutTan
.empty() && CInterfaceExpr::eval(rKey
.OutTan
, res
))
485 nlwarning ("cannot convert TanOut to double");
487 k
.TanOut
= (float)res
.getDouble();
494 if (!rKey
.Step
.empty() && CInterfaceExpr::eval(rKey
.Step
, res
))
497 nlwarning ("cannot convert Step to bool");
499 k
.Step
= res
.getBool();
506 _TrackKeyFramer
->addBezierFloatKey (k
);
509 default: nlstop
; break;
514 // ----------------------------------------------------------------------------
516 // ----------------------------------------------------------------------------
518 // ----------------------------------------------------------------------------
519 CInterfaceAnim::CInterfaceAnim()
524 _DisableButtons
= true;
525 _AnimHasToBeStopped
= false;
529 // ----------------------------------------------------------------------------
530 CInterfaceAnim::~CInterfaceAnim()
532 for (uint i
= 0; i
< _Tracks
.size(); ++i
)
536 // ----------------------------------------------------------------------------
537 bool CInterfaceAnim::parse (xmlNodePtr cur
, CInterfaceGroup
*parentGroup
)
541 ptr
= xmlGetProp (cur
, (xmlChar
*)"id");
542 _Id
= (const char*)ptr
;
544 ptr
= xmlGetProp (cur
, (xmlChar
*)"duration");
547 nlwarning("anim with no duration");
550 fromString((const char*)ptr
, _Duration
);
553 _Duration
*= CWidgetManager::getInstance()->getSystemOption(CWidgetManager::OptionMulCoefAnim
).getValFloat();
555 ptr
= xmlGetProp (cur
, (xmlChar
*)"disable_buttons");
557 _DisableButtons
= CInterfaceElement::convertBool(ptr
);
559 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"on_finish" );
560 if (ptr
) _AHOnFinish
= (const char *) ptr
;
561 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"on_finish_params" );
562 if (ptr
) _AHOnFinishParams
= (const char *) ptr
;
569 // Check that this is a key node
570 if ( stricmp((char*)cur
->name
,"track") != 0 )
576 CInterfaceTrack
*pTrack
= new CInterfaceTrack
;
577 if (!pTrack
->parse(cur
,parentGroup
))
580 nlwarning("track not added to anim");
584 _Tracks
.push_back(pTrack
);
589 _Parent
= parentGroup
;
594 // ----------------------------------------------------------------------------
595 void CInterfaceAnim::update()
597 if ((_Duration
== 0) || (_Finished
))
600 const CWidgetManager::SInterfaceTimes
×
= CWidgetManager::getInstance()->getInterfaceTimes();
602 // Delta time limiter
603 if ( ( times
.frameDiffMs
/ 1000.0f
) > 0.1)
606 _CurrentTime
+= ( times
.frameDiffMs
/ 1000.0f
);
608 // Stop the anim if we have to
609 if (_AnimHasToBeStopped
)
615 // Do this here to let it play the last frame of the animation
616 if (_CurrentTime
>= _Duration
)
618 _CurrentTime
= _Duration
;
619 _AnimHasToBeStopped
= true;
623 for (uint i
= 0; i
< _Tracks
.size(); ++i
)
625 CInterfaceTrack
*pTrack
= _Tracks
[i
];
626 pTrack
->update (_CurrentTime
);
630 // ----------------------------------------------------------------------------
631 void CInterfaceAnim::start()
635 _AnimHasToBeStopped
= false;
637 // Look if there are some dynamic tracks
638 for (uint i
= 0; i
< _Tracks
.size(); ++i
)
639 if (_Tracks
[i
]->isDynamic())
642 // Play the first frame
646 // ----------------------------------------------------------------------------
647 void CInterfaceAnim::stop()
651 if (!_AHOnFinish
.empty())
652 CAHManager::getInstance()->runActionHandler(_AHOnFinish
, _Parent
, _AHOnFinishParams
);