Change Encyclo button name and macros icon
[ryzomcore.git] / nel / src / gui / interface_anim.cpp
blob36a5d82f4c48dda0194710fad964dc9496b69c35
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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>
7 //
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/>.
21 #include "stdpch.h"
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 // ----------------------------------------------------------------------------
30 using namespace std;
31 using namespace NL3D;
32 using namespace NLMISC;
34 #ifdef DEBUG_NEW
35 #define new DEBUG_NEW
36 #endif
38 namespace NLGUI
41 // ----------------------------------------------------------------------------
42 // CInterfaceTrack
43 // ----------------------------------------------------------------------------
44 CInterfaceTrack::CInterfaceTrack()
46 _Type = Track_Linear;
47 _TrackKeyFramer = NULL;
48 _Dynamic = false;
51 // ----------------------------------------------------------------------------
52 CInterfaceTrack::~CInterfaceTrack()
54 delete _TrackKeyFramer;
57 // ----------------------------------------------------------------------------
58 bool CInterfaceTrack::parse (xmlNodePtr cur, CInterfaceGroup *parentGroup)
60 CXMLAutoPtr ptr;
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());
67 if (sTmp == "linear")
68 _Type = Track_Linear;
69 else if (sTmp == "bezier")
70 _Type = Track_Bezier;
71 else if (sTmp == "tcb")
72 _Type = Track_TCB;
73 else
74 nlwarning ("track unknown type : %s, setting linear by default", (const char*)ptr);
76 ptr = xmlGetProp (cur, (xmlChar*)"target");
77 if (!ptr)
79 nlwarning ("no target for track");
80 return false;
84 if (!CInterfaceLink::splitLinkTargets (ptr.str(), parentGroup, _Targets))
86 nlwarning ("no target for track");
87 return false;
90 // Initialize the track
91 switch(_Type)
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;
99 cur = cur->children;
100 bool ok = true;
102 if (_Dynamic)
104 while (cur)
106 // Check that this is a key node
107 if ( stricmp((char*)cur->name,"key") != 0 )
109 cur = cur->next;
110 continue;
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");
117 if (!time || !value)
119 nlwarning("track key with no time or no value");
120 ok = false;
121 cur = cur->next;
122 continue;
125 SDynKey k;
126 k.Value = (const char*)value;
127 k.Time = (const char*)time;
128 if (isdigit(k.Time[0]) || (k.Time[0] == '-'))
130 double dTime;
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
136 switch(_Type)
138 case Track_Linear:
139 break;
141 case Track_Bezier:
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;
152 break;
154 case Track_TCB:
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;
169 break;
170 default: nlstop; break;
172 _DynKeys.push_back(k);
174 cur = cur->next;
177 else // Static parsing
179 while (cur)
181 // Check that this is a key node
182 if ( stricmp((char*)cur->name,"key") != 0 )
184 cur = cur->next;
185 continue;
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");
192 if (!time || !value)
194 nlwarning("track key with no time or no value");
195 ok = false;
196 cur = cur->next;
197 continue;
200 float fAnimTime;
201 fromString((const char*)time, fAnimTime);
202 TAnimationTime animTime = fAnimTime * CWidgetManager::getInstance()->getSystemOption(CWidgetManager::OptionMulCoefAnim).getValFloat();
203 double animValue;
204 fromString(value.str(), animValue);
206 // Depending on the type of the track add the key
207 switch(_Type)
209 case Track_Linear:
211 UTrackKeyframer::UKeyLinearFloat k;
212 k.Time = animTime;
213 k.Value = (float)animValue;
214 _TrackKeyFramer->addLinearFloatKey (k);
216 break;
218 case Track_Bezier:
220 UTrackKeyframer::UKeyBezierFloat k;
221 k.Time = animTime;
222 k.Value = (float)animValue;
224 // Read extra values
225 CXMLAutoPtr inTan, outTan, step;
226 inTan = xmlGetProp (cur, (xmlChar*)"intan");
227 outTan = xmlGetProp (cur, (xmlChar*)"outtan");
228 step = xmlGetProp (cur, (xmlChar*)"step");
230 k.TanIn = 0.0f;
231 k.TanOut = 0.0f;
232 k.Step = false;
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);
240 break;
242 case Track_TCB:
244 UTrackKeyframer::UKeyTCBFloat k;
245 k.Time = animTime;
246 k.Value = (float)animValue;
248 // Read extra values
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");
256 k.Tension = 0.0f;
257 k.Continuity = 0.0f;
258 k.Bias = 0.0f;
259 k.EaseTo = 0.0f;
260 k.EaseFrom = 0.0f;
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);
270 break;
271 default: nlstop; break;
273 cur = cur->next;
276 return true;
279 // ----------------------------------------------------------------------------
280 void CInterfaceTrack::update (double currentTime)
282 float currentValue;
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;
302 switch(_Type)
304 case Track_Linear:
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))
314 if (!res.toDouble())
315 nlwarning ("cannot convert Time to double");
316 else
317 k.Time = (TAnimationTime)res.getDouble();
319 else
321 k.Time = 0;
324 if (!rKey.Value.empty() && CInterfaceExpr::eval(rKey.Value, res))
326 if (!res.toDouble())
327 nlwarning ("cannot convert Value to double");
328 else
329 k.Value = (float)res.getDouble();
331 else
333 k.Value = 0;
336 _TrackKeyFramer->addLinearFloatKey (k);
339 break;
341 case Track_TCB:
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))
351 if (!res.toDouble())
352 nlwarning ("cannot convert Time to double");
353 else
354 k.Time = (TAnimationTime)res.getDouble();
356 else
358 k.Time = 0;
361 if (!rKey.Value.empty() && CInterfaceExpr::eval(rKey.Value, res))
363 if (!res.toDouble())
364 nlwarning ("cannot convert Value to double");
365 else
366 k.Value = (float)res.getDouble();
368 else
370 k.Value = 0;
373 if (!rKey.Tension.empty() && CInterfaceExpr::eval(rKey.Tension, res))
375 if (!res.toDouble())
376 nlwarning ("cannot convert Tension to double");
377 else
378 k.Tension = (float)res.getDouble();
380 else
382 k.Tension = 0;
385 if (!rKey.Continuity.empty() && CInterfaceExpr::eval(rKey.Continuity, res))
387 if (!res.toDouble())
388 nlwarning ("cannot convert Continuity to double");
389 else
390 k.Continuity = (float)res.getDouble();
392 else
394 k.Continuity = 0;
397 if (!rKey.Bias.empty() && CInterfaceExpr::eval(rKey.Bias, res))
399 if (!res.toDouble())
400 nlwarning ("cannot convert Bias to double");
401 else
402 k.Bias = (float)res.getDouble();
404 else
406 k.Bias = 0;
409 if (!rKey.EaseTo.empty() && CInterfaceExpr::eval(rKey.EaseTo, res))
411 if (!res.toDouble())
412 nlwarning ("cannot convert EaseTo to double");
413 else
414 k.EaseTo = (float)res.getDouble();
416 else
418 k.EaseTo = 0;
421 if (!rKey.EaseFrom.empty() && CInterfaceExpr::eval(rKey.EaseFrom, res))
423 if (!res.toDouble())
424 nlwarning ("cannot convert EaseFrom to double");
425 else
426 k.EaseFrom = (float)res.getDouble();
428 else
430 k.EaseFrom = 0;
433 _TrackKeyFramer->addTCBFloatKey (k);
436 break;
438 case Track_Bezier:
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))
448 if (!res.toDouble())
449 nlwarning ("cannot convert Time to double");
450 else
451 k.Time = (TAnimationTime)res.getDouble();
453 else
455 k.Time = 0;
458 if (!rKey.Value.empty() && CInterfaceExpr::eval(rKey.Value, res))
460 if (!res.toDouble())
461 nlwarning ("cannot convert Value to double");
462 else
463 k.Value = (float)res.getDouble();
465 else
467 k.Value = 0;
470 if (!rKey.InTan.empty() && CInterfaceExpr::eval(rKey.InTan, res))
472 if (!res.toDouble())
473 nlwarning ("cannot convert TanIn to double");
474 else
475 k.TanIn = (float)res.getDouble();
477 else
479 k.TanIn = 0;
482 if (!rKey.OutTan.empty() && CInterfaceExpr::eval(rKey.OutTan, res))
484 if (!res.toDouble())
485 nlwarning ("cannot convert TanOut to double");
486 else
487 k.TanOut = (float)res.getDouble();
489 else
491 k.TanOut = 0;
494 if (!rKey.Step.empty() && CInterfaceExpr::eval(rKey.Step, res))
496 if (!res.toBool())
497 nlwarning ("cannot convert Step to bool");
498 else
499 k.Step = res.getBool();
501 else
503 k.Step = false;
506 _TrackKeyFramer->addBezierFloatKey (k);
509 default: nlstop; break;
514 // ----------------------------------------------------------------------------
515 // CInterfaceAnim
516 // ----------------------------------------------------------------------------
518 // ----------------------------------------------------------------------------
519 CInterfaceAnim::CInterfaceAnim()
521 _CurrentTime = 0;
522 _Finished = true;
523 _Duration = 0;
524 _DisableButtons = true;
525 _AnimHasToBeStopped = false;
526 _Parent = NULL;
529 // ----------------------------------------------------------------------------
530 CInterfaceAnim::~CInterfaceAnim()
532 for (uint i = 0; i < _Tracks.size(); ++i)
533 delete _Tracks[i];
536 // ----------------------------------------------------------------------------
537 bool CInterfaceAnim::parse (xmlNodePtr cur, CInterfaceGroup *parentGroup)
539 CXMLAutoPtr ptr;
541 ptr = xmlGetProp (cur, (xmlChar*)"id");
542 _Id = (const char*)ptr;
544 ptr = xmlGetProp (cur, (xmlChar*)"duration");
545 if (!ptr)
547 nlwarning("anim with no duration");
548 return false;
550 fromString((const char*)ptr, _Duration);
551 if (_Duration == 0)
552 _Duration = 1.0;
553 _Duration *= CWidgetManager::getInstance()->getSystemOption(CWidgetManager::OptionMulCoefAnim).getValFloat();
555 ptr = xmlGetProp (cur, (xmlChar*)"disable_buttons");
556 if (ptr)
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;
564 cur = cur->children;
566 // bool ok = true;
567 while (cur)
569 // Check that this is a key node
570 if ( stricmp((char*)cur->name,"track") != 0 )
572 cur = cur->next;
573 continue;
576 CInterfaceTrack *pTrack = new CInterfaceTrack;
577 if (!pTrack->parse(cur,parentGroup))
579 delete pTrack;
580 nlwarning("track not added to anim");
582 else
584 _Tracks.push_back(pTrack);
586 cur = cur->next;
589 _Parent = parentGroup;
591 return true;
594 // ----------------------------------------------------------------------------
595 void CInterfaceAnim::update()
597 if ((_Duration == 0) || (_Finished))
598 return;
600 const CWidgetManager::SInterfaceTimes &times = CWidgetManager::getInstance()->getInterfaceTimes();
602 // Delta time limiter
603 if ( ( times.frameDiffMs / 1000.0f ) > 0.1)
604 _CurrentTime += 0.1;
605 else
606 _CurrentTime += ( times.frameDiffMs / 1000.0f );
608 // Stop the anim if we have to
609 if (_AnimHasToBeStopped)
611 stop();
612 return;
615 // Do this here to let it play the last frame of the animation
616 if (_CurrentTime >= _Duration)
618 _CurrentTime = _Duration;
619 _AnimHasToBeStopped = true;
622 // Update tracks
623 for (uint i = 0; i < _Tracks.size(); ++i)
625 CInterfaceTrack *pTrack = _Tracks[i];
626 pTrack->update (_CurrentTime);
630 // ----------------------------------------------------------------------------
631 void CInterfaceAnim::start()
633 _CurrentTime = 0.0f;
634 _Finished = false;
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())
640 _Tracks[i]->eval();
642 // Play the first frame
643 update();
646 // ----------------------------------------------------------------------------
647 void CInterfaceAnim::stop()
649 _Finished = true;
651 if (!_AHOnFinish.empty())
652 CAHManager::getInstance()->runActionHandler(_AHOnFinish, _Parent, _AHOnFinishParams);