1*70f497fbSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*70f497fbSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*70f497fbSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*70f497fbSAndrew Rist  * distributed with this work for additional information
6*70f497fbSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*70f497fbSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*70f497fbSAndrew Rist  * "License"); you may not use this file except in compliance
9*70f497fbSAndrew Rist  * with the License.  You may obtain a copy of the License at
10*70f497fbSAndrew Rist  *
11*70f497fbSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*70f497fbSAndrew Rist  *
13*70f497fbSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*70f497fbSAndrew Rist  * software distributed under the License is distributed on an
15*70f497fbSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*70f497fbSAndrew Rist  * KIND, either express or implied.  See the License for the
17*70f497fbSAndrew Rist  * specific language governing permissions and limitations
18*70f497fbSAndrew Rist  * under the License.
19*70f497fbSAndrew Rist  *
20*70f497fbSAndrew Rist  *************************************************************/
21*70f497fbSAndrew Rist 
22*70f497fbSAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_slideshow.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir // must be first
28cdf0e10cSrcweir #include <canvas/debug.hxx>
29cdf0e10cSrcweir #include <canvas/verbosetrace.hxx>
30cdf0e10cSrcweir 
31cdf0e10cSrcweir #include <simplecontinuousactivitybase.hxx>
32cdf0e10cSrcweir 
33cdf0e10cSrcweir 
34cdf0e10cSrcweir namespace slideshow
35cdf0e10cSrcweir {
36cdf0e10cSrcweir     namespace internal
37cdf0e10cSrcweir     {
SimpleContinuousActivityBase(const ActivityParameters & rParms)38cdf0e10cSrcweir         SimpleContinuousActivityBase::SimpleContinuousActivityBase(
39cdf0e10cSrcweir             const ActivityParameters& rParms ) :
40cdf0e10cSrcweir             ActivityBase( rParms ),
41cdf0e10cSrcweir             maTimer( rParms.mrActivitiesQueue.getTimer() ),
42cdf0e10cSrcweir             mnMinSimpleDuration( rParms.mnMinDuration ),
43cdf0e10cSrcweir             mnMinNumberOfFrames( rParms.mnMinNumberOfFrames ),
44cdf0e10cSrcweir             mnCurrPerformCalls( 0 )
45cdf0e10cSrcweir         {
46cdf0e10cSrcweir         }
47cdf0e10cSrcweir 
startAnimation()48cdf0e10cSrcweir         void SimpleContinuousActivityBase::startAnimation()
49cdf0e10cSrcweir         {
50cdf0e10cSrcweir             // init timer. We measure animation time only when we're
51cdf0e10cSrcweir             // actually started.
52cdf0e10cSrcweir             maTimer.reset();
53cdf0e10cSrcweir         }
54cdf0e10cSrcweir 
calcTimeLag() const55cdf0e10cSrcweir         double SimpleContinuousActivityBase::calcTimeLag() const
56cdf0e10cSrcweir         {
57cdf0e10cSrcweir             ActivityBase::calcTimeLag();
58cdf0e10cSrcweir             if (! isActive())
59cdf0e10cSrcweir                 return 0.0;
60cdf0e10cSrcweir 
61cdf0e10cSrcweir             // retrieve locally elapsed time
62cdf0e10cSrcweir             const double nCurrElapsedTime( maTimer.getElapsedTime() );
63cdf0e10cSrcweir 
64cdf0e10cSrcweir             // log time
65cdf0e10cSrcweir             VERBOSE_TRACE( "SimpleContinuousActivityBase::calcTimeLag(): "
66cdf0e10cSrcweir                            "next step is based on time: %f", nCurrElapsedTime );
67cdf0e10cSrcweir 
68cdf0e10cSrcweir             // go to great length to ensure a proper animation
69cdf0e10cSrcweir             // run. Since we don't know how often we will be called
70cdf0e10cSrcweir             // here, try to spread the animator calls uniquely over
71cdf0e10cSrcweir             // the [0,1] parameter range. Be aware of the fact that
72cdf0e10cSrcweir             // perform will be called at least mnMinNumberOfTurns
73cdf0e10cSrcweir             // times.
74cdf0e10cSrcweir 
75cdf0e10cSrcweir             // fraction of time elapsed
76cdf0e10cSrcweir             const double nFractionElapsedTime(
77cdf0e10cSrcweir                 nCurrElapsedTime / mnMinSimpleDuration );
78cdf0e10cSrcweir 
79cdf0e10cSrcweir             // fraction of minimum calls performed
80cdf0e10cSrcweir             const double nFractionRequiredCalls(
81cdf0e10cSrcweir                 double(mnCurrPerformCalls) / mnMinNumberOfFrames );
82cdf0e10cSrcweir 
83cdf0e10cSrcweir             // okay, so now, the decision is easy:
84cdf0e10cSrcweir             //
85cdf0e10cSrcweir             // If the fraction of time elapsed is smaller than the
86cdf0e10cSrcweir             // number of calls required to be performed, then we calc
87cdf0e10cSrcweir             // the position on the animation range according to
88cdf0e10cSrcweir             // elapsed time. That is, we're so to say ahead of time.
89cdf0e10cSrcweir             //
90cdf0e10cSrcweir             // In contrary, if the fraction of time elapsed is larger,
91cdf0e10cSrcweir             // then we're lagging, and we thus calc the position on
92cdf0e10cSrcweir             // the animation time line according to the fraction of
93cdf0e10cSrcweir             // calls performed. Thus, the animation is forced to slow
94cdf0e10cSrcweir             // down, and take the required minimal number of steps,
95cdf0e10cSrcweir             // sufficiently equally distributed across the animation
96cdf0e10cSrcweir             // time line.
97cdf0e10cSrcweir             if( nFractionElapsedTime < nFractionRequiredCalls )
98cdf0e10cSrcweir             {
99cdf0e10cSrcweir                 VERBOSE_TRACE( "SimpleContinuousActivityBase::calcTimeLag(): "
100cdf0e10cSrcweir                                "t=%f is based on time", nFractionElapsedTime );
101cdf0e10cSrcweir                 return 0.0;
102cdf0e10cSrcweir             }
103cdf0e10cSrcweir             else
104cdf0e10cSrcweir             {
105cdf0e10cSrcweir                 VERBOSE_TRACE( "SimpleContinuousActivityBase::perform(): "
106cdf0e10cSrcweir                                "t=%f is based on number of calls",
107cdf0e10cSrcweir                                nFractionRequiredCalls );
108cdf0e10cSrcweir 
109cdf0e10cSrcweir                 // lag global time, so all other animations lag, too:
110cdf0e10cSrcweir                 return ((nFractionElapsedTime - nFractionRequiredCalls)
111cdf0e10cSrcweir                         * mnMinSimpleDuration);
112cdf0e10cSrcweir             }
113cdf0e10cSrcweir         }
114cdf0e10cSrcweir 
perform()115cdf0e10cSrcweir         bool SimpleContinuousActivityBase::perform()
116cdf0e10cSrcweir         {
117cdf0e10cSrcweir             // call base class, for start() calls and end handling
118cdf0e10cSrcweir             if( !ActivityBase::perform() )
119cdf0e10cSrcweir                 return false; // done, we're ended
120cdf0e10cSrcweir 
121cdf0e10cSrcweir 
122cdf0e10cSrcweir             // get relative animation position
123cdf0e10cSrcweir             // ===============================
124cdf0e10cSrcweir 
125cdf0e10cSrcweir             const double nCurrElapsedTime( maTimer.getElapsedTime() );
126cdf0e10cSrcweir             double nT( nCurrElapsedTime / mnMinSimpleDuration );
127cdf0e10cSrcweir 
128cdf0e10cSrcweir 
129cdf0e10cSrcweir             // one of the stop criteria reached?
130cdf0e10cSrcweir             // =================================
131cdf0e10cSrcweir 
132cdf0e10cSrcweir             // will be set to true below, if one of the termination criteria
133cdf0e10cSrcweir             // matched.
134cdf0e10cSrcweir             bool bActivityEnding( false );
135cdf0e10cSrcweir 
136cdf0e10cSrcweir             if( isRepeatCountValid() )
137cdf0e10cSrcweir             {
138cdf0e10cSrcweir                 // Finite duration
139cdf0e10cSrcweir                 // ===============
140cdf0e10cSrcweir 
141cdf0e10cSrcweir                 // When we've autoreverse on, the repeat count
142cdf0e10cSrcweir                 // doubles
143cdf0e10cSrcweir                 const double nRepeatCount( getRepeatCount() );
144cdf0e10cSrcweir                 const double nEffectiveRepeat( isAutoReverse() ?
145cdf0e10cSrcweir                                                2.0*nRepeatCount :
146cdf0e10cSrcweir                                                nRepeatCount );
147cdf0e10cSrcweir 
148cdf0e10cSrcweir                 // time (or frame count) elapsed?
149cdf0e10cSrcweir                 if( nEffectiveRepeat <= nT )
150cdf0e10cSrcweir                 {
151cdf0e10cSrcweir                     // okee. done for now. Will not exit right here,
152cdf0e10cSrcweir                     // to give animation the chance to render the last
153cdf0e10cSrcweir                     // frame below
154cdf0e10cSrcweir                     bActivityEnding = true;
155cdf0e10cSrcweir 
156cdf0e10cSrcweir                     // clamp animation to max permissible value
157cdf0e10cSrcweir                     nT = nEffectiveRepeat;
158cdf0e10cSrcweir                 }
159cdf0e10cSrcweir             }
160cdf0e10cSrcweir 
161cdf0e10cSrcweir 
162cdf0e10cSrcweir             // need to do auto-reverse?
163cdf0e10cSrcweir             // ========================
164cdf0e10cSrcweir 
165cdf0e10cSrcweir             double nRepeats;
166cdf0e10cSrcweir             double nRelativeSimpleTime;
167cdf0e10cSrcweir 
168cdf0e10cSrcweir             // TODO(Q3): Refactor this mess
169cdf0e10cSrcweir             if( isAutoReverse() )
170cdf0e10cSrcweir             {
171cdf0e10cSrcweir                 // divert active duration into repeat and
172cdf0e10cSrcweir                 // fractional part.
173cdf0e10cSrcweir                 const double nFractionalActiveDuration( modf(nT, &nRepeats) );
174cdf0e10cSrcweir 
175cdf0e10cSrcweir                 // for auto-reverse, map ranges [1,2), [3,4), ...
176cdf0e10cSrcweir                 // to ranges [0,1), [1,2), etc.
177cdf0e10cSrcweir                 if( ((int)nRepeats) % 2 )
178cdf0e10cSrcweir                 {
179cdf0e10cSrcweir                     // we're in an odd range, reverse sweep
180cdf0e10cSrcweir                     nRelativeSimpleTime = 1.0 - nFractionalActiveDuration;
181cdf0e10cSrcweir                 }
182cdf0e10cSrcweir                 else
183cdf0e10cSrcweir                 {
184cdf0e10cSrcweir                     // we're in an even range, pass on as is
185cdf0e10cSrcweir                     nRelativeSimpleTime = nFractionalActiveDuration;
186cdf0e10cSrcweir                 }
187cdf0e10cSrcweir 
188cdf0e10cSrcweir                 // effective repeat count for autoreverse is half of
189cdf0e10cSrcweir                 // the input time's value (each run of an autoreverse
190cdf0e10cSrcweir                 // cycle is half of a repeat)
191cdf0e10cSrcweir                 nRepeats /= 2;
192cdf0e10cSrcweir             }
193cdf0e10cSrcweir             else
194cdf0e10cSrcweir             {
195cdf0e10cSrcweir                 // determine repeat
196cdf0e10cSrcweir                 // ================
197cdf0e10cSrcweir 
198cdf0e10cSrcweir                 // calc simple time and number of repeats from nT
199cdf0e10cSrcweir                 // Now, that's easy, since the fractional part of
200cdf0e10cSrcweir                 // nT gives the relative simple time, and the
201cdf0e10cSrcweir                 // integer part the number of full repeats:
202cdf0e10cSrcweir                 nRelativeSimpleTime = modf(nT, &nRepeats);
203cdf0e10cSrcweir 
204cdf0e10cSrcweir                 // clamp repeats to max permissible value (maRepeats.getValue() - 1.0)
205cdf0e10cSrcweir                 if( isRepeatCountValid() &&
206cdf0e10cSrcweir                     nRepeats >= getRepeatCount() )
207cdf0e10cSrcweir                 {
208cdf0e10cSrcweir                     // Note that this code here only gets
209cdf0e10cSrcweir                     // triggered if maRepeats.getValue() is an
210cdf0e10cSrcweir                     // _integer_. Otherwise, nRepeats will never
211cdf0e10cSrcweir                     // reach nor exceed
212cdf0e10cSrcweir                     // maRepeats.getValue(). Thus, the code below
213cdf0e10cSrcweir                     // does not need to handle cases of fractional
214cdf0e10cSrcweir                     // repeats, and can always assume that a full
215cdf0e10cSrcweir                     // animation run has ended (with
216cdf0e10cSrcweir                     // nRelativeSimpleTime=1.0 for
217cdf0e10cSrcweir                     // non-autoreversed activities).
218cdf0e10cSrcweir 
219cdf0e10cSrcweir                     // with modf, nRelativeSimpleTime will never
220cdf0e10cSrcweir                     // become 1.0, since nRepeats is incremented and
221cdf0e10cSrcweir                     // nRelativeSimpleTime set to 0.0 then.
222cdf0e10cSrcweir                     //
223cdf0e10cSrcweir                     // For the animation to reach its final value,
224cdf0e10cSrcweir                     // nRepeats must although become
225cdf0e10cSrcweir                     // maRepeats.getValue()-1.0, and
226cdf0e10cSrcweir                     // nRelativeSimpleTime=1.0.
227cdf0e10cSrcweir                     nRelativeSimpleTime = 1.0;
228cdf0e10cSrcweir                     nRepeats -= 1.0;
229cdf0e10cSrcweir                 }
230cdf0e10cSrcweir             }
231cdf0e10cSrcweir 
232cdf0e10cSrcweir             // actually perform something
233cdf0e10cSrcweir             // ==========================
234cdf0e10cSrcweir 
235cdf0e10cSrcweir             simplePerform( nRelativeSimpleTime,
236cdf0e10cSrcweir                            // nRepeats is already integer-valued
237cdf0e10cSrcweir                            static_cast<sal_uInt32>( nRepeats ) );
238cdf0e10cSrcweir 
239cdf0e10cSrcweir 
240cdf0e10cSrcweir             // delayed endActivity() call from end condition check
241cdf0e10cSrcweir             // below. Issued after the simplePerform() call above, to
242cdf0e10cSrcweir             // give animations the chance to correctly reach the
243cdf0e10cSrcweir             // animation end value, without spurious bail-outs because
244cdf0e10cSrcweir             // of isActive() returning false.
245cdf0e10cSrcweir             if( bActivityEnding )
246cdf0e10cSrcweir                 endActivity();
247cdf0e10cSrcweir 
248cdf0e10cSrcweir             // one more frame successfully performed
249cdf0e10cSrcweir             ++mnCurrPerformCalls;
250cdf0e10cSrcweir 
251cdf0e10cSrcweir             return isActive();
252cdf0e10cSrcweir         }
253cdf0e10cSrcweir     }
254cdf0e10cSrcweir }
255